<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Anastasy</id>
	<title>Алговики - Вклад [ru]</title>
	<link rel="self" type="application/atom+xml" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Anastasy"/>
	<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/ru/%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/Anastasy"/>
	<updated>2026-10-22T22:31:12Z</updated>
	<subtitle>Вклад</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24613</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24613"/>
		<updated>2017-11-30T09:12:45Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Рисунок 1. Информационный граф алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Рисунок 2. Информационный граф поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Для алгоритма Диница:&lt;br /&gt;
# Инициализация переменных&lt;br /&gt;
# Вызов функции поиска в ширину&lt;br /&gt;
# (3.1 - 3.k) выполнение функции поиска в глубину, итеративно увеличивается поток &lt;br /&gt;
# Вызов функции поиска в ширину. В случае существования пути до стока, переход на следующую итерацию (начиная с поиска в глубину), иначе вывод вычисленной величины потока. &lt;br /&gt;
Для поиска в ширину&lt;br /&gt;
# Инициализация расстояния до истока (&amp;lt;math&amp;gt;d[s] = 0&amp;lt;/math&amp;gt;) и текущего уровня нулю (&amp;lt;math&amp;gt;level = 0&amp;lt;/math&amp;gt;). &lt;br /&gt;
# Извлечение очередной вершины из множества вершин, соответствующего процессу (&amp;lt;math&amp;gt;v \in V_{node}&amp;lt;/math&amp;gt;). Вершина обрабатывается, если расстояние до нее равно текущему уровню (&amp;lt;math&amp;gt;d[v] == level &amp;lt;/math&amp;gt;)&lt;br /&gt;
# Обход соседей вершин. В случае если вершина &amp;lt;math&amp;gt;u &amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, значение пути до этой вершины инициализируется &amp;lt;math&amp;gt;d[u] = level + 1&amp;lt;/math&amp;gt;. Иначе она помечается для дальнейшей обработки другим процессом.&lt;br /&gt;
# Слияние информации по помеченным вершинам (в общем массиве помечаются все вершины, которые были помечены хотя бы один раз)&lt;br /&gt;
# Для всех помеченных необработанных (&amp;lt;math&amp;gt;d[v] == -1 &amp;lt;/math&amp;gt;) вершин, принадлежащих  &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, расстояние принимается равным &amp;lt;math&amp;gt;level + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# Если было обновлено расстояние хотя бы до одной вершины, переход на следующую итерацию, иначе выход из цикла&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В приведенном варианте алгоритма поиска в ширину граф обходится по слоям, то есть на каждой итерации обрабатывается множество вершин, расстояние до которых одинаково. Число слоев не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, таким образом, высота ярусно-параллельной формы алгоритма поиска в ширину равна &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Так как поиск блокирующего потока производится последовательно, его высота ярусно-параллельной формы алгоритма совпадает с его последовательной сложностью &amp;lt;math&amp;gt;O(nm)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Так как число шагов алгоритма не превосходит &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, высота ЯПФ алгоритма Диница равна &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В описанном алгоритме поиска в ширину вершины разделяются между процессами поровну, поэтому ширина ЯПФ поиска в ширину и алгоритма Диница равна &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
В зависимости от порядка обработки ребер графа, вычисленные блокирующие потоки на соответствующих итерациях могут быть различны, кроме того, может поменяться количество итераций алгоритма Диница.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* число процессоров &amp;lt;math&amp;gt;[2^k, k = 0, 1, ...7]&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число вершин графа [5 000:20 000] с шагом 5000. Количество ребер одинаково для всех графов и равно 2 500 000.&lt;br /&gt;
На графике, приведенном ниже, показана зависимость производительности (количество обработанных ребер в единицу времени) от количества процессов и количества вершин графа. Время алгоритма сильно зависит от структуры графа (она влияет на количество итераций алгоритма Диница), поэтому время выполнения алгоритма в общем случае не пропорционально размеру графа. &lt;br /&gt;
&lt;br /&gt;
График зависимости ускорения от количества процессов и количества вершин графа (рис. 4) более нагляден, так как количество итераций в алгоритме не зависит от количества процессов и время выполнения пропорционально числу итераций. По этому графику видно, что ускорение падает с увеличением размера графа. &lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:Dinic scalability.png|thumb|none|600px|Рисунок 3. График зависимости производительности от количества процессов и количества вершин графа]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:speedup_dinic.png|thumb|none|600px|Рисунок 3. График зависимости производительности от количества процессов и количества вершин графа]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
*  Python:  [https://networkx.github.io NetworkX]  (функция &amp;lt;code&amp;gt;[https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.flow.dinitz.html dinitz]&amp;lt;/code&amp;gt;): алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24612</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24612"/>
		<updated>2017-11-30T09:10:13Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Рисунок 1. Информационный граф алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Рисунок 2. Информационный граф поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Для алгоритма Диница:&lt;br /&gt;
# Инициализация переменных&lt;br /&gt;
# Вызов функции поиска в ширину&lt;br /&gt;
# (3.1 - 3.k) выполнение функции поиска в глубину, итеративно увеличивается поток &lt;br /&gt;
# Вызов функции поиска в ширину. В случае существования пути до стока, переход на следующую итерацию (начиная с поиска в глубину), иначе вывод вычисленной величины потока. &lt;br /&gt;
Для поиска в ширину&lt;br /&gt;
# Инициализация расстояния до истока (&amp;lt;math&amp;gt;d[s] = 0&amp;lt;/math&amp;gt;) и текущего уровня нулю (&amp;lt;math&amp;gt;level = 0&amp;lt;/math&amp;gt;). &lt;br /&gt;
# Извлечение очередной вершины из множества вершин, соответствующего процессу (&amp;lt;math&amp;gt;v \in V_{node}&amp;lt;/math&amp;gt;). Вершина обрабатывается, если расстояние до нее равно текущему уровню (&amp;lt;math&amp;gt;d[v] == level &amp;lt;/math&amp;gt;)&lt;br /&gt;
# Обход соседей вершин. В случае если вершина &amp;lt;math&amp;gt;u &amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, значение пути до этой вершины инициализируется &amp;lt;math&amp;gt;d[u] = level + 1&amp;lt;/math&amp;gt;. Иначе она помечается для дальнейшей обработки другим процессом.&lt;br /&gt;
# Слияние информации по помеченным вершинам (в общем массиве помечаются все вершины, которые были помечены хотя бы один раз)&lt;br /&gt;
# Для всех помеченных необработанных (&amp;lt;math&amp;gt;d[v] == -1 &amp;lt;/math&amp;gt;) вершин, принадлежащих  &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, расстояние принимается равным &amp;lt;math&amp;gt;level + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# Если было обновлено расстояние хотя бы до одной вершины, переход на следующую итерацию, иначе выход из цикла&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В приведенном варианте алгоритма поиска в ширину граф обходится по слоям, то есть на каждой итерации обрабатывается множество вершин, расстояние до которых одинаково. Число слоев не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, таким образом, высота ярусно-параллельной формы алгоритма поиска в ширину равна &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Так как поиск блокирующего потока производится последовательно, его высота ярусно-параллельной формы алгоритма совпадает с его последовательной сложностью &amp;lt;math&amp;gt;O(nm)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Так как число шагов алгоритма не превосходит &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, высота ЯПФ алгоритма Диница равна &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В описанном алгоритме поиска в ширину вершины разделяются между процессами поровну, поэтому ширина ЯПФ поиска в ширину и алгоритма Диница равна &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
В зависимости от порядка обработки ребер графа, вычисленные блокирующие потоки на соответствующих итерациях могут быть различны, кроме того, может поменяться количество итераций алгоритма Диница.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* число процессоров &amp;lt;math&amp;gt;[2^k, k = 0, 1, ...7]&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число вершин графа [5 000:20 000] с шагом 5000. Количество ребер одинаково для всех графов и равно 2 500 000.&lt;br /&gt;
На графике, приведенном ниже, показана зависимость производительности (количество обработанных ребер в единицу времени) от количества процессов и количества вершин графа. Время алгоритма сильно зависит от структуры графа (она влияет на количество итераций алгоритма Диница), поэтому время выполнения алгоритма в общем случае не пропорционально размеру графа. &lt;br /&gt;
&lt;br /&gt;
График зависимости ускорения от количества процессов и количества вершин графа (рис. 4) более нагляден, так как количество итераций в алгоритме не зависит от количества процессов и время выполнения пропорционально числу итераций. По этому графику видно, что ускорение падает с увеличением размера графа. &lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:Dinic scalability.png|thumb|none|600px|Рисунок 3. График зависимости производительности от количества процессов и количества вершин графа]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
*  Python:  [https://networkx.github.io NetworkX]  (функция &amp;lt;code&amp;gt;[https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.flow.dinitz.html dinitz]&amp;lt;/code&amp;gt;): алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24600</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24600"/>
		<updated>2017-11-30T08:44:46Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Рисунок 1. Информационный граф алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Рисунок 2. Информационный граф поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Для алгоритма Диница:&lt;br /&gt;
# Инициализация переменных&lt;br /&gt;
# Вызов функции поиска в ширину&lt;br /&gt;
# (3.1 - 3.k) выполнение функции поиска в глубину, итеративно увеличивается поток &lt;br /&gt;
# Вызов функции поиска в ширину. В случае существования пути до стока, переход на следующую итерацию (начиная с поиска в глубину), иначе вывод вычисленной величины потока. &lt;br /&gt;
Для поиска в ширину&lt;br /&gt;
# Инициализация расстояния до истока (&amp;lt;math&amp;gt;d[s] = 0&amp;lt;/math&amp;gt;) и текущего уровня нулю (&amp;lt;math&amp;gt;level = 0&amp;lt;/math&amp;gt;). &lt;br /&gt;
# Извлечение очередной вершины из множества вершин, соответствующего процессу (&amp;lt;math&amp;gt;v \in V_{node}&amp;lt;/math&amp;gt;). Вершина обрабатывается, если расстояние до нее равно текущему уровню (&amp;lt;math&amp;gt;d[v] == level &amp;lt;/math&amp;gt;)&lt;br /&gt;
# Обход соседей вершин. В случае если вершина &amp;lt;math&amp;gt;u &amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, значение пути до этой вершины инициализируется &amp;lt;math&amp;gt;d[u] = level + 1&amp;lt;/math&amp;gt;. Иначе она помечается для дальнейшей обработки другим процессом.&lt;br /&gt;
# Слияние информации по помеченным вершинам (в общем массиве помечаются все вершины, которые были помечены хотя бы один раз)&lt;br /&gt;
# Для всех помеченных необработанных (&amp;lt;math&amp;gt;d[v] == -1 &amp;lt;/math&amp;gt;) вершин, принадлежащих  &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, расстояние принимается равным &amp;lt;math&amp;gt;level + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# Если было обновлено расстояние хотя бы до одной вершины, переход на следующую итерацию, иначе выход из цикла&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В приведенном варианте алгоритма поиска в ширину граф обходится по слоям, то есть на каждой итерации обрабатывается множество вершин, расстояние до которых одинаково. Число слоев не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, таким образом, высота ярусно-параллельной формы алгоритма поиска в ширину равна &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Так как поиск блокирующего потока производится последовательно, его высота ярусно-параллельной формы алгоритма совпадает с его последовательной сложностью &amp;lt;math&amp;gt;O(nm)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Так как число шагов алгоритма не превосходит &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, высота ЯПФ алгоритма Диница равна &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В описанном алгоритме поиска в ширину вершины разделяются между процессами поровну, поэтому ширина ЯПФ поиска в ширину и алгоритма Диница равна &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
В зависимости от порядка обработки ребер графа, вычисленные блокирующие потоки на соответствующих итерациях могут быть различны, кроме того, может поменяться количество итераций алгоритма Диница.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* число процессоров &amp;lt;math&amp;gt;[2^k, k = 0, 1, ...7]&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число вершин графа [5 000:20 000] с шагом 5000. Количество ребер одинаково для всех графов и равно 2 500 000.&lt;br /&gt;
На графике, приведенном ниже, показана зависимость производительности (количество обработанных ребер в единицу времени) от количества процессов и количества вершин графа. Время алгоритма сильно зависит от структуры графа (она влияет на количество итераций алгоритма Диница), поэтому время выполнения алгоритма в общем случае не пропорционально размеру графа. &lt;br /&gt;
&lt;br /&gt;
Для большей наглядности на рисунке 4 приведен график зависимости ускорения от количества процессов и количества вершин графа. Так как &lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:Dinic scalability.png|thumb|none|600px|Рисунок 3. График зависимости производительности от количества процессов и количества вершин графа]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
*  Python:  [https://networkx.github.io NetworkX]  (функция &amp;lt;code&amp;gt;[https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.flow.dinitz.html dinitz]&amp;lt;/code&amp;gt;): алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24514</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24514"/>
		<updated>2017-11-29T18:52:34Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Существующие реализации алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Рисунок 1. Информационный граф алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Рисунок 2. Информационный граф поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Для алгоритма Диница:&lt;br /&gt;
# Инициализация переменных&lt;br /&gt;
# Вызов функции поиска в ширину&lt;br /&gt;
# (3.1 - 3.k) выполнение функции поиска в глубину, итеративно увеличивается поток &lt;br /&gt;
# Вызов функции поиска в ширину. В случае существования пути до стока, переход на следующую итерацию (начиная с поиска в глубину), иначе вывод вычисленной величины потока. &lt;br /&gt;
Для поиска в ширину&lt;br /&gt;
# Инициализация расстояния до истока (&amp;lt;math&amp;gt;d[s] = 0&amp;lt;/math&amp;gt;) и текущего уровня нулю (&amp;lt;math&amp;gt;level = 0&amp;lt;/math&amp;gt;). &lt;br /&gt;
# Извлечение очередной вершины из множества вершин, соответствующего процессу (&amp;lt;math&amp;gt;v \in V_{node}&amp;lt;/math&amp;gt;). Вершина обрабатывается, если расстояние до нее равно текущему уровню (&amp;lt;math&amp;gt;d[v] == level &amp;lt;/math&amp;gt;)&lt;br /&gt;
# Обход соседей вершин. В случае если вершина &amp;lt;math&amp;gt;u &amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, значение пути до этой вершины инициализируется &amp;lt;math&amp;gt;d[u] = level + 1&amp;lt;/math&amp;gt;. Иначе она помечается для дальнейшей обработки другим процессом.&lt;br /&gt;
# Слияние информации по помеченным вершинам (в общем массиве помечаются все вершины, которые были помечены хотя бы один раз)&lt;br /&gt;
# Для всех помеченных необработанных (&amp;lt;math&amp;gt;d[v] == -1 &amp;lt;/math&amp;gt;) вершин, принадлежащих  &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, расстояние принимается равным &amp;lt;math&amp;gt;level + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# Если было обновлено расстояние хотя бы до одной вершины, переход на следующую итерацию, иначе выход из цикла&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В приведенном варианте алгоритма поиска в ширину граф обходится по слоям, то есть на каждой итерации обрабатывается множество вершин, расстояние до которых одинаково. Число слоев не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, таким образом, высота ярусно-параллельной формы алгоритма поиска в ширину равна &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Так как поиск блокирующего потока производится последовательно, его высота ярусно-параллельной формы алгоритма совпадает с его последовательной сложностью &amp;lt;math&amp;gt;O(nm)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Так как число шагов алгоритма не превосходит &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, высота ЯПФ алгоритма Диница равна &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В описанном алгоритме поиска в ширину вершины разделяются между процессами поровну, поэтому ширина ЯПФ поиска в ширину и алгоритма Диница равна &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
В зависимости от порядка обработки ребер графа, вычисленные блокирующие потоки на соответствующих итерациях могут быть различны, кроме того, может поменяться количество итераций алгоритма Диница.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* число процессоров &amp;lt;math&amp;gt;[2^k, k = 0, 1, ...7]&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число вершин графа [5 000:20 000] с шагом 5000. Количество ребер одинаково для всех графов и равно 2 500 000.&lt;br /&gt;
На графике, приведенном ниже, показана зависимость производительности (количество обработанных ребер в единицу времени) от количества процессов и количества вершин графа. Время алгоритма сильно зависит от структуры графа (она влияет на количество итераций алгоритма Диница), поэтому время выполнения алгоритма в общем случае не пропорционально размеру графа. &lt;br /&gt;
&lt;br /&gt;
[[File:Dinic scalability.png|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
*  Python:  [https://networkx.github.io NetworkX]  (функция &amp;lt;code&amp;gt;[https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.flow.dinitz.html dinitz]&amp;lt;/code&amp;gt;): алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24500</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24500"/>
		<updated>2017-11-29T18:00:16Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Рисунок 1. Информационный граф алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Рисунок 2. Информационный граф поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Для алгоритма Диница:&lt;br /&gt;
# Инициализация переменных&lt;br /&gt;
# Вызов функции поиска в ширину&lt;br /&gt;
# (3.1 - 3.k) выполнение функции поиска в глубину, итеративно увеличивается поток &lt;br /&gt;
# Вызов функции поиска в ширину. В случае существования пути до стока, переход на следующую итерацию (начиная с поиска в глубину), иначе вывод вычисленной величины потока. &lt;br /&gt;
Для поиска в ширину&lt;br /&gt;
# Инициализация расстояния до истока (&amp;lt;math&amp;gt;d[s] = 0&amp;lt;/math&amp;gt;) и текущего уровня нулю (&amp;lt;math&amp;gt;level = 0&amp;lt;/math&amp;gt;). &lt;br /&gt;
# Извлечение очередной вершины из множества вершин, соответствующего процессу (&amp;lt;math&amp;gt;v \in V_{node}&amp;lt;/math&amp;gt;). Вершина обрабатывается, если расстояние до нее равно текущему уровню (&amp;lt;math&amp;gt;d[v] == level &amp;lt;/math&amp;gt;)&lt;br /&gt;
# Обход соседей вершин. В случае если вершина &amp;lt;math&amp;gt;u &amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, значение пути до этой вершины инициализируется &amp;lt;math&amp;gt;d[u] = level + 1&amp;lt;/math&amp;gt;. Иначе она помечается для дальнейшей обработки другим процессом.&lt;br /&gt;
# Слияние информации по помеченным вершинам (в общем массиве помечаются все вершины, которые были помечены хотя бы один раз)&lt;br /&gt;
# Для всех помеченных необработанных (&amp;lt;math&amp;gt;d[v] == -1 &amp;lt;/math&amp;gt;) вершин, принадлежащих  &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, расстояние принимается равным &amp;lt;math&amp;gt;level + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# Если было обновлено расстояние хотя бы до одной вершины, переход на следующую итерацию, иначе выход из цикла&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В приведенном варианте алгоритма поиска в ширину граф обходится по слоям, то есть на каждой итерации обрабатывается множество вершин, расстояние до которых одинаково. Число слоев не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, таким образом, высота ярусно-параллельной формы алгоритма поиска в ширину равна &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Так как поиск блокирующего потока производится последовательно, его высота ярусно-параллельной формы алгоритма совпадает с его последовательной сложностью &amp;lt;math&amp;gt;O(nm)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Так как число шагов алгоритма не превосходит &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, высота ЯПФ алгоритма Диница равна &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В описанном алгоритме поиска в ширину вершины разделяются между процессами поровну, поэтому ширина ЯПФ поиска в ширину и алгоритма Диница равна &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
В зависимости от порядка обработки ребер графа, вычисленные блокирующие потоки на соответствующих итерациях могут быть различны, кроме того, может поменяться количество итераций алгоритма Диница.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* число процессоров &amp;lt;math&amp;gt;[2^k, k = 0, 1, ...7]&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число вершин графа [5 000:20 000] с шагом 5000. Количество ребер одинаково для всех графов и равно 2 500 000.&lt;br /&gt;
На графике, приведенном ниже, показана зависимость производительности (количество обработанных ребер в единицу времени) от количества процессов и количества вершин графа. Время алгоритма сильно зависит от структуры графа (она влияет на количество итераций алгоритма Диница), поэтому время выполнения алгоритма в общем случае не пропорционально размеру графа. &lt;br /&gt;
&lt;br /&gt;
[[File:Dinic scalability.png|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24499</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24499"/>
		<updated>2017-11-29T17:59:22Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Информационный граф алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Информационный граф поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Для алгоритма Диница:&lt;br /&gt;
# Инициализация переменных&lt;br /&gt;
# Вызов функции поиска в ширину&lt;br /&gt;
# (3.1 - 3.k) выполнение функции поиска в глубину, итеративно увеличивается поток &lt;br /&gt;
# Вызов функции поиска в ширину. В случае существования пути до стока, переход на следующую итерацию (начиная с поиска в глубину), иначе вывод вычисленной величины потока. &lt;br /&gt;
Для поиска в ширину&lt;br /&gt;
# Инициализация расстояния до истока (&amp;lt;math&amp;gt;d[s] = 0&amp;lt;/math&amp;gt;) и текущего уровня нулю (&amp;lt;math&amp;gt;level = 0&amp;lt;/math&amp;gt;). &lt;br /&gt;
# Извлечение очередной вершины из множества вершин, соответствующего процессу (&amp;lt;math&amp;gt;v \in V_{node}&amp;lt;/math&amp;gt;). Вершина обрабатывается, если расстояние до нее равно текущему уровню (&amp;lt;math&amp;gt;d[v] == level &amp;lt;/math&amp;gt;)&lt;br /&gt;
# Обход соседей вершин. В случае если вершина &amp;lt;math&amp;gt;u &amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, значение пути до этой вершины инициализируется &amp;lt;math&amp;gt;d[u] = level + 1&amp;lt;/math&amp;gt;. Иначе она помечается для дальнейшей обработки другим процессом.&lt;br /&gt;
# Слияние информации по помеченным вершинам (в общем массиве помечаются все вершины, которые были помечены хотя бы один раз)&lt;br /&gt;
# Для всех помеченных необработанных (&amp;lt;math&amp;gt;d[v] == -1 &amp;lt;/math&amp;gt;) вершин, принадлежащих  &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, расстояние принимается равным &amp;lt;math&amp;gt;level + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# Если было обновлено расстояние хотя бы до одной вершины, переход на следующую итерацию, иначе выход из цикла&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В приведенном варианте алгоритма поиска в ширину граф обходится по слоям, то есть на каждой итерации обрабатывается множество вершин, расстояние до которых одинаково. Число слоев не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, таким образом, высота ярусно-параллельной формы алгоритма поиска в ширину равна &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Так как поиск блокирующего потока производится последовательно, его высота ярусно-параллельной формы алгоритма совпадает с его последовательной сложностью &amp;lt;math&amp;gt;O(nm)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Так как число шагов алгоритма не превосходит &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, высота ЯПФ алгоритма Диница равна &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В описанном алгоритме поиска в ширину вершины разделяются между процессами поровну, поэтому ширина ЯПФ поиска в ширину и алгоритма Диница равна &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
В зависимости от порядка обработки ребер графа, вычисленные блокирующие потоки на соответствующих итерациях могут быть различны, кроме того, может поменяться количество итераций алгоритма Диница.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* число процессоров &amp;lt;math&amp;gt;[2^k, k = 0, 1, ...7]&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число вершин графа [5 000:20 000] с шагом 5000. Количество ребер одинаково для всех графов и равно 2 500 000.&lt;br /&gt;
На графике, приведенном ниже, показана зависимость производительности (количество обработанных ребер в единицу времени) от количества процессов и количества вершин графа. Время алгоритма сильно зависит от структуры графа (она влияет на количество итераций алгоритма Диница), поэтому время выполнения алгоритма в общем случае не пропорционально размеру графа. &lt;br /&gt;
&lt;br /&gt;
[[File:Dinic scalability.png|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24486</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24486"/>
		<updated>2017-11-29T16:09:24Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Общее описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Информационный граф алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Информационный граф поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Для алгоритма Диница:&lt;br /&gt;
# Инициализация переменных&lt;br /&gt;
# Вызов функции поиска в ширину&lt;br /&gt;
# (3.1 - 3.k) выполнение функции поиска в глубину, итеративно увеличивается поток &lt;br /&gt;
# Вызов функции поиска в ширину. В случае существования пути до стока, переход на следующую итерацию (начиная с поиска в глубину), иначе вывод вычисленной величины потока. &lt;br /&gt;
Для поиска в ширину&lt;br /&gt;
# Инициализация расстояния до истока (&amp;lt;math&amp;gt;d[s] = 0&amp;lt;/math&amp;gt;) и текущего уровня нулю (&amp;lt;math&amp;gt;level = 0&amp;lt;/math&amp;gt;). &lt;br /&gt;
# Извлечение очередной вершины из множества вершин, соответствующего процессу (&amp;lt;math&amp;gt;v \in V_{node}&amp;lt;/math&amp;gt;). Вершина обрабатывается, если расстояние до нее равно текущему уровню (&amp;lt;math&amp;gt;d[v] == level &amp;lt;/math&amp;gt;)&lt;br /&gt;
# Обход соседей вершин. В случае если вершина &amp;lt;math&amp;gt;u &amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, значение пути до этой вершины инициализируется &amp;lt;math&amp;gt;d[u] = level + 1&amp;lt;/math&amp;gt;. Иначе она помечается для дальнейшей обработки другим процессом.&lt;br /&gt;
# Слияние информации по помеченным вершинам (в общем массиве помечаются все вершины, которые были помечены хотя бы один раз)&lt;br /&gt;
# Для всех помеченных необработанных (&amp;lt;math&amp;gt;d[v] == -1 &amp;lt;/math&amp;gt;) вершин, принадлежащих  &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, расстояние принимается равным &amp;lt;math&amp;gt;level + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# Если было обновлено расстояние хотя бы до одной вершины, переход на следующую итерацию, иначе выход из цикла&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В приведенном варианте алгоритма поиска в ширину граф обходится по слоям, то есть на каждой итерации обрабатывается множество вершин, расстояние до которых одинаково. Число слоев не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, таким образом, высота ярусно-параллельной формы алгоритма поиска в ширину равна &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Так как поиск блокирующего потока производится последовательно, его высота ярусно-параллельной формы алгоритма совпадает с его последовательной сложностью &amp;lt;math&amp;gt;O(nm)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Так как число шагов алгоритма не превосходит &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, высота ЯПФ алгоритма Диница равна &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В описанном алгоритме поиска в ширину вершины разделяются между процессами поровну, поэтому ширина ЯПФ поиска в ширину и алгоритма Диница равна &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
В зависимости от порядка обработки ребер графа, вычисленные блокирующие потоки на соответствующих итерациях могут быть различны, кроме того, может поменяться количество итераций алгоритма Диница.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* число процессоров &amp;lt;math&amp;gt;[2^k, k = 0, 1, ...7]&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число вершин графа [5 000:20 000] с шагом 5000. Количество ребер одинаково для всех графов и равно 2 500 000.&lt;br /&gt;
&lt;br /&gt;
[[File:Dinic scalability.png|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24389</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24389"/>
		<updated>2017-11-28T11:44:56Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Информационный граф алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Информационный граф поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Для алгоритма Диница:&lt;br /&gt;
# Инициализация переменных&lt;br /&gt;
# Вызов функции поиска в ширину&lt;br /&gt;
# (3.1 - 3.k) выполнение функции поиска в глубину, итеративно увеличивается поток &lt;br /&gt;
# Вызов функции поиска в ширину. В случае существования пути до стока, переход на следующую итерацию (начиная с поиска в глубину), иначе вывод вычисленной величины потока. &lt;br /&gt;
Для поиска в ширину&lt;br /&gt;
# Инициализация расстояния до истока (&amp;lt;math&amp;gt;d[s] = 0&amp;lt;/math&amp;gt;) и текущего уровня нулю (&amp;lt;math&amp;gt;level = 0&amp;lt;/math&amp;gt;). &lt;br /&gt;
# Извлечение очередной вершины из множества вершин, соответствующего процессу (&amp;lt;math&amp;gt;v \in V_{node}&amp;lt;/math&amp;gt;). Вершина обрабатывается, если расстояние до нее равно текущему уровню (&amp;lt;math&amp;gt;d[v] == level &amp;lt;/math&amp;gt;)&lt;br /&gt;
# Обход соседей вершин. В случае если вершина &amp;lt;math&amp;gt;u &amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, значение пути до этой вершины инициализируется &amp;lt;math&amp;gt;d[u] = level + 1&amp;lt;/math&amp;gt;. Иначе она помечается для дальнейшей обработки другим процессом.&lt;br /&gt;
# Слияние информации по помеченным вершинам (в общем массиве помечаются все вершины, которые были помечены хотя бы один раз)&lt;br /&gt;
# Для всех помеченных необработанных (&amp;lt;math&amp;gt;d[v] == -1 &amp;lt;/math&amp;gt;) вершин, принадлежащих  &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, расстояние принимается равным &amp;lt;math&amp;gt;level + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# Если было обновлено расстояние хотя бы до одной вершины, переход на следующую итерацию, иначе выход из цикла&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В приведенном варианте алгоритма поиска в ширину граф обходится по слоям, то есть на каждой итерации обрабатывается множество вершин, расстояние до которых одинаково. Число слоев не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, таким образом, высота ярусно-параллельной формы алгоритма поиска в ширину равна &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Так как поиск блокирующего потока производится последовательно, его высота ярусно-параллельной формы алгоритма совпадает с его последовательной сложностью &amp;lt;math&amp;gt;O(nm)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Так как число шагов алгоритма не превосходит &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, высота ЯПФ алгоритма Диница равна &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В описанном алгоритме поиска в ширину вершины разделяются между процессами поровну, поэтому ширина ЯПФ поиска в ширину и алгоритма Диница равна &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
В зависимости от порядка обработки ребер графа, вычисленные блокирующие потоки на соответствующих итерациях могут быть различны, кроме того, может поменяться количество итераций алгоритма Диница.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* число процессоров &amp;lt;math&amp;gt;[2^k, k = 0, 1, ...7]&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число вершин графа [5 000:20 000] с шагом 5000. Количество ребер одинаково для всех графов и равно 2 500 000.&lt;br /&gt;
&lt;br /&gt;
[[File:Dinic scalability.png|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24388</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24388"/>
		<updated>2017-11-28T11:44:37Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Масштабируемость алгоритма и его реализации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Информационный граф алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Информационный граф поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Для алгоритма Диница:&lt;br /&gt;
# Инициализация переменных&lt;br /&gt;
# Вызов функции поиска в ширину&lt;br /&gt;
# (3.1 - 3.k) выполнение функции поиска в глубину, итеративно увеличивается поток &lt;br /&gt;
# Вызов функции поиска в ширину. В случае существования пути до стока, переход на следующую итерацию (начиная с поиска в глубину), иначе вывод вычисленной величины потока. &lt;br /&gt;
Для поиска в ширину&lt;br /&gt;
# Инициализация расстояния до истока (&amp;lt;math&amp;gt;d[s] = 0&amp;lt;/math&amp;gt;) и текущего уровня нулю (&amp;lt;math&amp;gt;level = 0&amp;lt;/math&amp;gt;). &lt;br /&gt;
# Извлечение очередной вершины из множества вершин, соответствующего процессу (&amp;lt;math&amp;gt;v \in V_{node}&amp;lt;/math&amp;gt;). Вершина обрабатывается, если расстояние до нее равно текущему уровню (&amp;lt;math&amp;gt;d[v] == level &amp;lt;/math&amp;gt;)&lt;br /&gt;
# Обход соседей вершин. В случае если вершина &amp;lt;math&amp;gt;u &amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, значение пути до этой вершины инициализируется &amp;lt;math&amp;gt;d[u] = level + 1&amp;lt;/math&amp;gt;. Иначе она помечается для дальнейшей обработки другим процессом.&lt;br /&gt;
# Слияние информации по помеченным вершинам (в общем массиве помечаются все вершины, которые были помечены хотя бы один раз)&lt;br /&gt;
# Для всех помеченных необработанных (&amp;lt;math&amp;gt;d[v] == -1 &amp;lt;/math&amp;gt;) вершин, принадлежащих  &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, расстояние принимается равным &amp;lt;math&amp;gt;level + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# Если было обновлено расстояние хотя бы до одной вершины, переход на следующую итерацию, иначе выход из цикла&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В приведенном варианте алгоритма поиска в ширину граф обходится по слоям, то есть на каждой итерации обрабатывается множество вершин, расстояние до которых одинаково. Число слоев не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, таким образом, высота ярусно-параллельной формы алгоритма поиска в ширину равна &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Так как поиск блокирующего потока производится последовательно, его высота ярусно-параллельной формы алгоритма совпадает с его последовательной сложностью &amp;lt;math&amp;gt;O(nm)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Так как число шагов алгоритма не превосходит &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, высота ЯПФ алгоритма Диница равна &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В описанном алгоритме поиска в ширину вершины разделяются между процессами поровну, поэтому ширина ЯПФ поиска в ширину и алгоритма Диница равна &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
В зависимости от порядка обработки ребер графа, вычисленные блокирующие потоки на соответствующих итерациях могут быть различны, кроме того, может поменяться количество итераций алгоритма Диница.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
Набор и границы значений изменяемых параметров запуска реализации алгоритма:&lt;br /&gt;
&lt;br /&gt;
* число процессоров &amp;lt;math&amp;gt;[2^k, k = 0, 1, ...7]&amp;lt;/math&amp;gt;;&lt;br /&gt;
* число вершин графа [5000:20000] с шагом 5000. Количество ребер одинаково для всех графов и равно 2500000.&lt;br /&gt;
&lt;br /&gt;
[[File:Dinic scalability.png|600px]]&lt;br /&gt;
&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24387</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24387"/>
		<updated>2017-11-28T11:36:39Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Свойства алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Информационный граф алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Информационный граф поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Для алгоритма Диница:&lt;br /&gt;
# Инициализация переменных&lt;br /&gt;
# Вызов функции поиска в ширину&lt;br /&gt;
# (3.1 - 3.k) выполнение функции поиска в глубину, итеративно увеличивается поток &lt;br /&gt;
# Вызов функции поиска в ширину. В случае существования пути до стока, переход на следующую итерацию (начиная с поиска в глубину), иначе вывод вычисленной величины потока. &lt;br /&gt;
Для поиска в ширину&lt;br /&gt;
# Инициализация расстояния до истока (&amp;lt;math&amp;gt;d[s] = 0&amp;lt;/math&amp;gt;) и текущего уровня нулю (&amp;lt;math&amp;gt;level = 0&amp;lt;/math&amp;gt;). &lt;br /&gt;
# Извлечение очередной вершины из множества вершин, соответствующего процессу (&amp;lt;math&amp;gt;v \in V_{node}&amp;lt;/math&amp;gt;). Вершина обрабатывается, если расстояние до нее равно текущему уровню (&amp;lt;math&amp;gt;d[v] == level &amp;lt;/math&amp;gt;)&lt;br /&gt;
# Обход соседей вершин. В случае если вершина &amp;lt;math&amp;gt;u &amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, значение пути до этой вершины инициализируется &amp;lt;math&amp;gt;d[u] = level + 1&amp;lt;/math&amp;gt;. Иначе она помечается для дальнейшей обработки другим процессом.&lt;br /&gt;
# Слияние информации по помеченным вершинам (в общем массиве помечаются все вершины, которые были помечены хотя бы один раз)&lt;br /&gt;
# Для всех помеченных необработанных (&amp;lt;math&amp;gt;d[v] == -1 &amp;lt;/math&amp;gt;) вершин, принадлежащих  &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, расстояние принимается равным &amp;lt;math&amp;gt;level + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# Если было обновлено расстояние хотя бы до одной вершины, переход на следующую итерацию, иначе выход из цикла&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В приведенном варианте алгоритма поиска в ширину граф обходится по слоям, то есть на каждой итерации обрабатывается множество вершин, расстояние до которых одинаково. Число слоев не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, таким образом, высота ярусно-параллельной формы алгоритма поиска в ширину равна &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Так как поиск блокирующего потока производится последовательно, его высота ярусно-параллельной формы алгоритма совпадает с его последовательной сложностью &amp;lt;math&amp;gt;O(nm)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Так как число шагов алгоритма не превосходит &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, высота ЯПФ алгоритма Диница равна &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В описанном алгоритме поиска в ширину вершины разделяются между процессами поровну, поэтому ширина ЯПФ поиска в ширину и алгоритма Диница равна &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
В зависимости от порядка обработки ребер графа, вычисленные блокирующие потоки на соответствующих итерациях могут быть различны, кроме того, может поменяться количество итераций алгоритма Диница.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24386</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24386"/>
		<updated>2017-11-28T11:23:24Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Ресурс параллелизма алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Информационный граф алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Информационный граф поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Для алгоритма Диница:&lt;br /&gt;
# Инициализация переменных&lt;br /&gt;
# Вызов функции поиска в ширину&lt;br /&gt;
# (3.1 - 3.k) выполнение функции поиска в глубину, итеративно увеличивается поток &lt;br /&gt;
# Вызов функции поиска в ширину. В случае существования пути до стока, переход на следующую итерацию (начиная с поиска в глубину), иначе вывод вычисленной величины потока. &lt;br /&gt;
Для поиска в ширину&lt;br /&gt;
# Инициализация расстояния до истока (&amp;lt;math&amp;gt;d[s] = 0&amp;lt;/math&amp;gt;) и текущего уровня нулю (&amp;lt;math&amp;gt;level = 0&amp;lt;/math&amp;gt;). &lt;br /&gt;
# Извлечение очередной вершины из множества вершин, соответствующего процессу (&amp;lt;math&amp;gt;v \in V_{node}&amp;lt;/math&amp;gt;). Вершина обрабатывается, если расстояние до нее равно текущему уровню (&amp;lt;math&amp;gt;d[v] == level &amp;lt;/math&amp;gt;)&lt;br /&gt;
# Обход соседей вершин. В случае если вершина &amp;lt;math&amp;gt;u &amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, значение пути до этой вершины инициализируется &amp;lt;math&amp;gt;d[u] = level + 1&amp;lt;/math&amp;gt;. Иначе она помечается для дальнейшей обработки другим процессом.&lt;br /&gt;
# Слияние информации по помеченным вершинам (в общем массиве помечаются все вершины, которые были помечены хотя бы один раз)&lt;br /&gt;
# Для всех помеченных необработанных (&amp;lt;math&amp;gt;d[v] == -1 &amp;lt;/math&amp;gt;) вершин, принадлежащих  &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, расстояние принимается равным &amp;lt;math&amp;gt;level + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# Если было обновлено расстояние хотя бы до одной вершины, переход на следующую итерацию, иначе выход из цикла&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В приведенном варианте алгоритма поиска в ширину граф обходится по слоям, то есть на каждой итерации обрабатывается множество вершин, расстояние до которых одинаково. Число слоев не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, таким образом, высота ярусно-параллельной формы алгоритма поиска в ширину равна &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Так как поиск блокирующего потока производится последовательно, его высота ярусно-параллельной формы алгоритма совпадает с его последовательной сложностью &amp;lt;math&amp;gt;O(nm)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Так как число шагов алгоритма не превосходит &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, высота ЯПФ алгоритма Диница равна &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В описанном алгоритме поиска в ширину вершины разделяются между процессами поровну, поэтому ширина ЯПФ поиска в ширину и алгоритма Диница равна &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24385</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24385"/>
		<updated>2017-11-28T11:23:12Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Ресурс параллелизма алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Информационный граф алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Информационный граф поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Для алгоритма Диница:&lt;br /&gt;
# Инициализация переменных&lt;br /&gt;
# Вызов функции поиска в ширину&lt;br /&gt;
# (3.1 - 3.k) выполнение функции поиска в глубину, итеративно увеличивается поток &lt;br /&gt;
# Вызов функции поиска в ширину. В случае существования пути до стока, переход на следующую итерацию (начиная с поиска в глубину), иначе вывод вычисленной величины потока. &lt;br /&gt;
Для поиска в ширину&lt;br /&gt;
# Инициализация расстояния до истока (&amp;lt;math&amp;gt;d[s] = 0&amp;lt;/math&amp;gt;) и текущего уровня нулю (&amp;lt;math&amp;gt;level = 0&amp;lt;/math&amp;gt;). &lt;br /&gt;
# Извлечение очередной вершины из множества вершин, соответствующего процессу (&amp;lt;math&amp;gt;v \in V_{node}&amp;lt;/math&amp;gt;). Вершина обрабатывается, если расстояние до нее равно текущему уровню (&amp;lt;math&amp;gt;d[v] == level &amp;lt;/math&amp;gt;)&lt;br /&gt;
# Обход соседей вершин. В случае если вершина &amp;lt;math&amp;gt;u &amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, значение пути до этой вершины инициализируется &amp;lt;math&amp;gt;d[u] = level + 1&amp;lt;/math&amp;gt;. Иначе она помечается для дальнейшей обработки другим процессом.&lt;br /&gt;
# Слияние информации по помеченным вершинам (в общем массиве помечаются все вершины, которые были помечены хотя бы один раз)&lt;br /&gt;
# Для всех помеченных необработанных (&amp;lt;math&amp;gt;d[v] == -1 &amp;lt;/math&amp;gt;) вершин, принадлежащих  &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, расстояние принимается равным &amp;lt;math&amp;gt;level + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# Если было обновлено расстояние хотя бы до одной вершины, переход на следующую итерацию, иначе выход из цикла&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма ===&lt;br /&gt;
В приведенном варианте алгоритма поиска в ширину, граф обходится по слоям, то есть на каждой итерации обрабатывается множество вершин, расстояние до которых одинаково. Число слоев не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, таким образом, высота ярусно-параллельной формы алгоритма поиска в ширину равна &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Так как поиск блокирующего потока производится последовательно, его высота ярусно-параллельной формы алгоритма совпадает с его последовательной сложностью &amp;lt;math&amp;gt;O(nm)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Так как число шагов алгоритма не превосходит &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;, высота ЯПФ алгоритма Диница равна &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В описанном алгоритме поиска в ширину вершины разделяются между процессами поровну, поэтому ширина ЯПФ поиска в ширину и алгоритма Диница равна &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24384</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24384"/>
		<updated>2017-11-28T11:00:38Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Информационный граф алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Информационный граф поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Для алгоритма Диница:&lt;br /&gt;
# Инициализация переменных&lt;br /&gt;
# Вызов функции поиска в ширину&lt;br /&gt;
# (3.1 - 3.k) выполнение функции поиска в глубину, итеративно увеличивается поток &lt;br /&gt;
# Вызов функции поиска в ширину. В случае существования пути до стока, переход на следующую итерацию (начиная с поиска в глубину), иначе вывод вычисленной величины потока. &lt;br /&gt;
Для поиска в ширину&lt;br /&gt;
# Инициализация расстояния до истока (&amp;lt;math&amp;gt;d[s] = 0&amp;lt;/math&amp;gt;) и текущего уровня нулю (&amp;lt;math&amp;gt;level = 0&amp;lt;/math&amp;gt;). &lt;br /&gt;
# Извлечение очередной вершины из множества вершин, соответствующего процессу (&amp;lt;math&amp;gt;v \in V_{node}&amp;lt;/math&amp;gt;). Вершина обрабатывается, если расстояние до нее равно текущему уровню (&amp;lt;math&amp;gt;d[v] == level &amp;lt;/math&amp;gt;)&lt;br /&gt;
# Обход соседей вершин. В случае если вершина &amp;lt;math&amp;gt;u &amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, значение пути до этой вершины инициализируется &amp;lt;math&amp;gt;d[u] = level + 1&amp;lt;/math&amp;gt;. Иначе она помечается для дальнейшей обработки другим процессом.&lt;br /&gt;
# Слияние информации по помеченным вершинам (в общем массиве помечаются все вершины, которые были помечены хотя бы один раз)&lt;br /&gt;
# Для всех помеченных необработанных (&amp;lt;math&amp;gt;d[v] == -1 &amp;lt;/math&amp;gt;) вершин, принадлежащих  &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, расстояние принимается равным &amp;lt;math&amp;gt;level + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# Если было обновлено расстояние хотя бы до одной вершины, переход на следующую итерацию, иначе выход из цикла&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24383</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24383"/>
		<updated>2017-11-28T10:46:02Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Информационный граф алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Информационный граф поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Для алгоритма Диница:&lt;br /&gt;
# Инициализация переменных&lt;br /&gt;
# Вызов функции поиска в ширину&lt;br /&gt;
# (3.1 - 3.k) выполнение функции поиска в глубину, итеративно увеличивается поток &lt;br /&gt;
# Вызов функции поиска в ширину. В случае существования пути до стока, переход на следующую итерацию (начиная с поиска в глубину), иначе вывод вычисленной величины потока. &lt;br /&gt;
Для поиска в ширину&lt;br /&gt;
# Инициализация расстояния до истока (&amp;lt;math&amp;gt;d[s] = 0&amp;lt;/math&amp;gt;). &lt;br /&gt;
# Проверка равенства расстояния до вершины из множества вершин, соответствующего процессу (&amp;lt;math&amp;gt;v \in V_{node}&amp;lt;/math&amp;gt;), текущему уровню (вершина обрабатывается, если &amp;lt;math&amp;gt;d[v] == level &amp;lt;/math&amp;gt;)&lt;br /&gt;
# Обход соседей вершин. В случае если вершина &amp;lt;math&amp;gt;u &amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, значение пути до этой вершины инициализируется &amp;lt;math&amp;gt;d[u] = level + 1&amp;lt;/math&amp;gt;. Иначе она помечается для дальнейшей обработки другим процессом.&lt;br /&gt;
# Слияние информации по помеченным вершинам (в общем массиве помечаются все вершины, которые были помечены хотя бы один раз)&lt;br /&gt;
# Для всех помеченных вершин, принадлежащих  &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, расстояние принимается равным &amp;lt;math&amp;gt;level + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# Если было обновлено расстояние хотя бы до одной вершины, переход на следующую итерацию, иначе выход из цикла&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24382</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24382"/>
		<updated>2017-11-28T10:43:17Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Информационный граф алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Информационный граф поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Для алгоритма Диница:&lt;br /&gt;
# Инициализация переменных&lt;br /&gt;
# Вызов функции поиска в ширину&lt;br /&gt;
# (3.1 - 3.k) выполнение функции поиска в глубину, итеративно увеличивается поток &lt;br /&gt;
# Вызов функции поиска в ширину. В случае существования пути до стока, переход на следующую итерацию (начиная с поиска в глубину), иначе вывод вычисленной величины потока. &lt;br /&gt;
Для поиска в ширину&lt;br /&gt;
# Передача данных по изменению ребер графа (удаляются насыщенные потоком ребра и добавляются те, в которых поток отрицателен)&lt;br /&gt;
# Проверка равенства расстояния до вершины из множества вершин, соответствующего процессу (&amp;lt;math&amp;gt;v \in V_{node}&amp;lt;/math&amp;gt;), текущему уровню (вершина обрабатывается, если &amp;lt;math&amp;gt;d[v] == level &amp;lt;/math&amp;gt;)&lt;br /&gt;
# Обход соседей вершин. В случае если вершина &amp;lt;math&amp;gt;u &amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, значение пути до этой вершины инициализируется &amp;lt;math&amp;gt;d[u] = level + 1&amp;lt;/math&amp;gt;. Иначе она помечается для дальнейшей обработки другим процессом.&lt;br /&gt;
# Слияние информации по помеченным вершинам (в общем массиве помечаются все вершины, которые были помечены хотя бы один раз)&lt;br /&gt;
# Для всех помеченных вершин, принадлежащих  &amp;lt;math&amp;gt;V_{node}&amp;lt;/math&amp;gt;, расстояние принимается равным &amp;lt;math&amp;gt;level + 1&amp;lt;/math&amp;gt;&lt;br /&gt;
# Если было обновлено расстояние хотя бы до одной вершины, переход на следующую итерацию, иначе выход из цикла&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24363</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24363"/>
		<updated>2017-11-27T20:19:26Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Информационный граф для алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Информационный граф для параллельной реализации поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
Для алгоритма Диница:&lt;br /&gt;
# Инициализация переменных&lt;br /&gt;
# Вызов функции поиска в ширину&lt;br /&gt;
# (3.1 - 3.k) выполнение функции поиска в глубину, итеративно увеличивается поток &lt;br /&gt;
# Вызов функции поиска в ширину. В случае существования пути до стока, переход на следующую итерацию (начиная с поиска в глубину), иначе вывод вычисленной величины потока. &lt;br /&gt;
Для параллельной реализации поиска в ширину&lt;br /&gt;
# Передача данных по изменению ребер графа (удаляются насыщенные потоком ребра и добавляются те, в которых поток отрицателен)&lt;br /&gt;
# Проверка равенства расстояния до вершины из множества вершин, соответствующего процессу (&amp;lt;math&amp;gt;v \in V.this\_node&amp;lt;/math&amp;gt;), текущему уровню (вершина обрабатывается, если &amp;lt;math&amp;gt;d[v] == level &amp;lt;/math&amp;gt;)&lt;br /&gt;
# Обход соседей вершин. В случае если вершина &amp;lt;math&amp;gt;to &amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;V.this\_node&amp;lt;/math&amp;gt;, значение пути до этой вершины инициализируется &amp;lt;math&amp;gt;d[to] == level + 1&amp;lt;/math&amp;gt;. Иначе она помечается для дальнейшей обработки другим процессом.&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24356</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24356"/>
		<updated>2017-11-27T18:57:58Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:dinic.png|thumb|none|500px|Информационный граф для алгоритма Диница]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li style=&amp;quot;display: inline-block;&amp;quot;&amp;gt; [[File:bfs.png|thumb|none|650px|Информационный граф для параллельной реализации поиска в ширину]] &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24355</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24355"/>
		<updated>2017-11-27T18:40:05Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Информационный граф */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[Файл:bfs.png|500px]]&lt;br /&gt;
&lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24134</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24134"/>
		<updated>2017-11-22T15:18:45Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Входные и выходные данные алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф === &lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер &amp;lt;math&amp;gt;e_j = (v_j^{(1)}, v_j^{(2)}) &amp;lt;/math&amp;gt; с заданной пропускной способностью &amp;lt;math&amp;gt;c_j&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(m + n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24133</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24133"/>
		<updated>2017-11-22T15:17:29Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Входные и выходные данные алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф === &lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039;: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер с заданной пропускной способностью &amp;lt;math&amp;gt;e_j = (v_j^(1), v_j^(2), c_j)&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем входных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(V + E)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039;: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем выходных данных&#039;&#039;&#039;: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24132</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=24132"/>
		<updated>2017-11-22T15:16:46Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Входные и выходные данные алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф === &lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
Входные данные: Граф &amp;lt;math&amp;gt;G(V, E)&amp;lt;/math&amp;gt;. &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин &amp;lt;math&amp;gt;v_i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; ребер с заданной пропускной способностью &amp;lt;math&amp;gt;e_j = (v_j^(1), v_j^(2), c_j)&amp;lt;/math&amp;gt;, а также исток &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; и сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Объем входных данных: &amp;lt;math&amp;gt;O(V + E)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выходные данные: величина максимального потока. &lt;br /&gt;
&lt;br /&gt;
Объем выходных данных: &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23857</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23857"/>
		<updated>2017-11-09T16:52:57Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Постановка задачи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt; (то есть &amp;lt;math&amp;gt;{\rm level&#039;}[t] &amp;gt; {\rm level}[t]&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;{\rm level&#039;}[t]&amp;lt;/math&amp;gt; — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф === &lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23856</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23856"/>
		<updated>2017-11-09T16:50:13Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Постановка задачи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref name=&amp;quot;Dinic&amp;quot;&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref name=&amp;quot;Dinic&amp;quot;/&amp;gt;, тогда так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф === &lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23855</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23855"/>
		<updated>2017-11-09T16:46:57Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Постановка задачи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается&amp;lt;ref&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt;, тогда так как длина кратчайшего &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути не может превосходить &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;, то и количество фаз алгоритма не превосходит &amp;lt;math&amp;gt;n - 1&amp;lt;/math&amp;gt;. Таким образом, весь алгоритм Диница выполняется за &amp;lt;math&amp;gt;O(n^2m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф === &lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23854</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23854"/>
		<updated>2017-11-09T16:43:17Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Можно показать, что каждый раз количество рёбер в блокирующем потоке увеличивается хотя бы на одно,&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф === &lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23853</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23853"/>
		<updated>2017-11-09T16:22:33Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Последовательная сложность алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
* С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;&lt;br /&gt;
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается &amp;lt;math&amp;gt;O(mn)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Информационный граф === &lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23852</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23852"/>
		<updated>2017-11-09T16:21:38Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Постановка задачи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
# С помощью поиска в ширину слоистая сеть строится за время &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;&lt;br /&gt;
# Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за &amp;lt;math&amp;gt;O(n + k)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет &amp;lt;math&amp;gt;O(p)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;p&amp;lt;/math&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;math&amp;gt;O(pn + \sum\limits_i{k_i})&amp;lt;/math&amp;gt;. Учитывая, что все указатели в сумме прошли расстояние &amp;lt;math&amp;gt;O(m)&amp;lt;/math&amp;gt;, это дает асимптотику &amp;lt;math&amp;gt;O(pn + pk)&amp;lt;/math&amp;gt;. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается O(VE).&lt;br /&gt;
=== Информационный граф === &lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23738</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23738"/>
		<updated>2017-11-03T19:51:04Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Киреева Анастасия, группа 416&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
=== Информационный граф === &lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23737</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23737"/>
		<updated>2017-11-03T19:49:53Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Постановка задачи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
&lt;br /&gt;
Автор: Анастасия Киреева&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
=== Информационный граф === &lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23736</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23736"/>
		<updated>2017-11-03T19:49:14Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Постановка задачи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Диница&lt;br /&gt;
Автор: Анастасия Киреева&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
=== Информационный граф === &lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23109</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23109"/>
		<updated>2017-10-20T14:42:27Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Программная реализация алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
=== Информационный граф === &lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
=== Особенности реализации последовательного алгоритма === &lt;br /&gt;
=== Локальность данных и вычислений ===&lt;br /&gt;
=== Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
=== Масштабируемость алгоритма и его реализации ===&lt;br /&gt;
=== Динамические характеристики и эффективность реализации алгоритма ===&lt;br /&gt;
=== Выводы для классов архитектур ===&lt;br /&gt;
=== Существующие реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23108</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23108"/>
		<updated>2017-10-20T14:40:50Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Постановка задачи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
=== Последовательная сложность алгоритма ===&lt;br /&gt;
=== Информационный граф === &lt;br /&gt;
=== Ресурс параллелизма алгоритма === &lt;br /&gt;
=== Входные и выходные данные алгоритма ===&lt;br /&gt;
=== Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23107</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23107"/>
		<updated>2017-10-20T14:28:55Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Постановка задачи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* [[Поиск в ширину (BFS)|поиск в ширину]] (для построения слоистой сети)&lt;br /&gt;
* [[Поиск в глубину (DFS)|обход в глубину]] (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23106</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23106"/>
		<updated>2017-10-20T14:27:27Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Математическое описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* поиск в ширину (для построения слоистой сети)&lt;br /&gt;
* обход в глубину (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23105</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23105"/>
		<updated>2017-10-20T14:26:26Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Математическое описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока s до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, для которых верно &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* поиск в ширину (для построения слоистой сети)&lt;br /&gt;
* обход в глубину (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23104</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23104"/>
		<updated>2017-10-20T14:25:20Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Общее описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока s до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, которые ведут с одного уровня на какой-либо другой, более поздний, уровень, т.е. &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt; (разница расстояний не может превосходить единицы,  это следует из свойства кратчайших расстояний). Таким образом, удаляются все рёбра, расположенные целиком внутри уровней, а также рёбра, ведущие назад, к предыдущим уровням.&lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* поиск в ширину (для построения слоистой сети)&lt;br /&gt;
* обход в глубину (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23103</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23103"/>
		<updated>2017-10-20T14:23:59Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Общее описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Yefim Dinitz (1970). &amp;quot;Algorithm for solution of a problem of maximum flow in a network with power estimation&amp;quot;. Доклады Академии наук СССР.&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока s до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, которые ведут с одного уровня на какой-либо другой, более поздний, уровень, т.е. &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt; (разница расстояний не может превосходить единицы,  это следует из свойства кратчайших расстояний). Таким образом, удаляются все рёбра, расположенные целиком внутри уровней, а также рёбра, ведущие назад, к предыдущим уровням.&lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* поиск в ширину (для построения слоистой сети)&lt;br /&gt;
* обход в глубину (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23102</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23102"/>
		<updated>2017-10-20T14:23:05Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Схема реализации последовательного алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Yefim Dinitz (1970). &amp;quot;Algorithm for solution of a problem of maximum flow in a network with power estimation&amp;quot;. Doklady Akademii nauk SSSR.&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока s до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, которые ведут с одного уровня на какой-либо другой, более поздний, уровень, т.е. &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt; (разница расстояний не может превосходить единицы,  это следует из свойства кратчайших расстояний). Таким образом, удаляются все рёбра, расположенные целиком внутри уровней, а также рёбра, ведущие назад, к предыдущим уровням.&lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* поиск в ширину (для построения слоистой сети)&lt;br /&gt;
* обход в глубину (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Затем строим слоистую сеть &amp;lt;math&amp;gt;G^L&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23101</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23101"/>
		<updated>2017-10-20T14:18:10Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Постановка задачи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Yefim Dinitz (1970). &amp;quot;Algorithm for solution of a problem of maximum flow in a network with power estimation&amp;quot;. Doklady Akademii nauk SSSR.&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока s до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, которые ведут с одного уровня на какой-либо другой, более поздний, уровень, т.е. &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt; (разница расстояний не может превосходить единицы,  это следует из свойства кратчайших расстояний). Таким образом, удаляются все рёбра, расположенные целиком внутри уровней, а также рёбра, ведущие назад, к предыдущим уровням.&lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* поиск в ширину (для построения слоистой сети)&lt;br /&gt;
* обход в глубину (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt;, алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23100</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23100"/>
		<updated>2017-10-20T14:17:34Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Постановка задачи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Yefim Dinitz (1970). &amp;quot;Algorithm for solution of a problem of maximum flow in a network with power estimation&amp;quot;. Doklady Akademii nauk SSSR.&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока s до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, которые ведут с одного уровня на какой-либо другой, более поздний, уровень, т.е. &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt; (разница расстояний не может превосходить единицы,  это следует из свойства кратчайших расстояний). Таким образом, удаляются все рёбра, расположенные целиком внутри уровней, а также рёбра, ведущие назад, к предыдущим уровням.&lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* поиск в ширину (для построения слоистой сети)&lt;br /&gt;
* обход в глубину (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать. &lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
=== Схема реализации последовательного алгоритма === &lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt; алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23099</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23099"/>
		<updated>2017-10-20T08:11:30Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Макроструктура алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Yefim Dinitz (1970). &amp;quot;Algorithm for solution of a problem of maximum flow in a network with power estimation&amp;quot;. Doklady Akademii nauk SSSR.&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока s до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, которые ведут с одного уровня на какой-либо другой, более поздний, уровень, т.е. &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt; (разница расстояний не может превосходить единицы,  это следует из свойства кратчайших расстояний). Таким образом, удаляются все рёбра, расположенные целиком внутри уровней, а также рёбра, ведущие назад, к предыдущим уровням.&lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* поиск в ширину (для построения слоистой сети)&lt;br /&gt;
* обход в глубину (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt; алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
==== Поиск блокирующего потока ====&lt;br /&gt;
Ищем &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23098</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23098"/>
		<updated>2017-10-20T08:02:59Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Макроструктура алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Yefim Dinitz (1970). &amp;quot;Algorithm for solution of a problem of maximum flow in a network with power estimation&amp;quot;. Doklady Akademii nauk SSSR.&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока s до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, которые ведут с одного уровня на какой-либо другой, более поздний, уровень, т.е. &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt; (разница расстояний не может превосходить единицы,  это следует из свойства кратчайших расстояний). Таким образом, удаляются все рёбра, расположенные целиком внутри уровней, а также рёбра, ведущие назад, к предыдущим уровням.&lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* поиск в ширину (для построения слоистой сети)&lt;br /&gt;
* обход в глубину (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
Структуру алгоритма можно описать следующим образом:&lt;br /&gt;
# Для всех ребер &amp;lt;math&amp;gt;(u, v) \in E&amp;lt;/math&amp;gt; сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; присвоим &amp;lt;math&amp;gt;f_{uv}=0&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Построим остаточную сеть &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;. Если &amp;lt;math&amp;gt;{\rm level}[t]=∞&amp;lt;/math&amp;gt; алгоритм завершает работу и выводит поток &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Ищем блокирующий поток &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; в сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt;&lt;br /&gt;
# Прибавим &amp;lt;math&amp;gt;f&#039;&amp;lt;/math&amp;gt; к потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; и переходим к шагу 2.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23087</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23087"/>
		<updated>2017-10-19T15:23:45Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Вычислительное ядро алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Yefim Dinitz (1970). &amp;quot;Algorithm for solution of a problem of maximum flow in a network with power estimation&amp;quot;. Doklady Akademii nauk SSSR.&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока s до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, которые ведут с одного уровня на какой-либо другой, более поздний, уровень, т.е. &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt; (разница расстояний не может превосходить единицы,  это следует из свойства кратчайших расстояний). Таким образом, удаляются все рёбра, расположенные целиком внутри уровней, а также рёбра, ведущие назад, к предыдущим уровням.&lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* поиск в ширину (для построения слоистой сети)&lt;br /&gt;
* обход в глубину (для построения блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23086</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23086"/>
		<updated>2017-10-19T15:23:31Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Вычислительное ядро алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Yefim Dinitz (1970). &amp;quot;Algorithm for solution of a problem of maximum flow in a network with power estimation&amp;quot;. Doklady Akademii nauk SSSR.&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока s до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, которые ведут с одного уровня на какой-либо другой, более поздний, уровень, т.е. &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt; (разница расстояний не может превосходить единицы,  это следует из свойства кратчайших расстояний). Таким образом, удаляются все рёбра, расположенные целиком внутри уровней, а также рёбра, ведущие назад, к предыдущим уровням.&lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на:&lt;br /&gt;
* поиск в ширину (для построения слоистой сети)&lt;br /&gt;
* обход в глубину (для построеия блокирующего потока)&lt;br /&gt;
&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23085</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23085"/>
		<updated>2017-10-19T15:22:59Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Постановка задачи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Yefim Dinitz (1970). &amp;quot;Algorithm for solution of a problem of maximum flow in a network with power estimation&amp;quot;. Doklady Akademii nauk SSSR.&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока s до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, которые ведут с одного уровня на какой-либо другой, более поздний, уровень, т.е. &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt; (разница расстояний не может превосходить единицы,  это следует из свойства кратчайших расстояний). Таким образом, удаляются все рёбра, расположенные целиком внутри уровней, а также рёбра, ведущие назад, к предыдущим уровням.&lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
=== Вычислительное ядро алгоритма ===&lt;br /&gt;
Наибольший объем вычислений приходится на&lt;br /&gt;
* поиск в ширину (для построения слоистой сети)&lt;br /&gt;
* обход в глубину (для построеия блокирующего потока)&lt;br /&gt;
=== Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23084</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23084"/>
		<updated>2017-10-19T15:14:13Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Математическое описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Yefim Dinitz (1970). &amp;quot;Algorithm for solution of a problem of maximum flow in a network with power estimation&amp;quot;. Doklady Akademii nauk SSSR.&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока s до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, которые ведут с одного уровня на какой-либо другой, более поздний, уровень, т.е. &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt; (разница расстояний не может превосходить единицы,  это следует из свойства кратчайших расстояний). Таким образом, удаляются все рёбра, расположенные целиком внутри уровней, а также рёбра, ведущие назад, к предыдущим уровням.&lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23083</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23083"/>
		<updated>2017-10-19T15:12:21Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Математическое описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Yefim Dinitz (1970). &amp;quot;Algorithm for solution of a problem of maximum flow in a network with power estimation&amp;quot;. Doklady Akademii nauk SSSR.&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G=(V, E)&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in E&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро (то есть &amp;lt;math&amp;gt;c_{uv} = f_{uv}&amp;lt;/math&amp;gt; для некоторых &amp;lt;math&amp;gt;u,v \in V&amp;lt;/math&amp;gt;. Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока s до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, которые ведут с одного уровня на какой-либо другой, более поздний, уровень, т.е. &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt; (разница расстояний не может превосходить единицы,  это следует из свойства кратчайших расстояний). Таким образом, удаляются все рёбра, расположенные целиком внутри уровней, а также рёбра, ведущие назад, к предыдущим уровням.&lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23082</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23082"/>
		<updated>2017-10-19T15:08:03Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Общее описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Yefim Dinitz (1970). &amp;quot;Algorithm for solution of a problem of maximum flow in a network with power estimation&amp;quot;. Doklady Akademii nauk SSSR.&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in G&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро. Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока s до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, которые ведут с одного уровня на какой-либо другой, более поздний, уровень, т.е. &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt; (разница расстояний не может превосходить единицы,  это следует из свойства кратчайших расстояний). Таким образом, удаляются все рёбра, расположенные целиком внутри уровней, а также рёбра, ведущие назад, к предыдущим уровням.&lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23081</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23081"/>
		<updated>2017-10-19T15:06:29Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Общее описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Yefim Dinitz (1970). &amp;quot;Algorithm for solution of a problem of maximum flow in a network with power estimation&amp;quot; (PDF). Doklady Akademii nauk SSSR.&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; —  число ребер, а &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; —  число вершин. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in G&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро. Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока s до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, которые ведут с одного уровня на какой-либо другой, более поздний, уровень, т.е. &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt; (разница расстояний не может превосходить единицы,  это следует из свойства кратчайших расстояний). Таким образом, удаляются все рёбра, расположенные целиком внутри уровней, а также рёбра, ведущие назад, к предыдущим уровням.&lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23080</id>
		<title>Участник:Anastasy/Алгоритм Диница</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Anastasy/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B8%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=23080"/>
		<updated>2017-10-19T15:04:59Z</updated>

		<summary type="html">&lt;p&gt;Anastasy: /* Математическое описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Постановка задачи ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Алгоритм Диница &amp;lt;ref&amp;gt;Yefim Dinitz (1970). &amp;quot;Algorithm for solution of a problem of maximum flow in a network with power estimation&amp;quot; (PDF). Doklady Akademii nauk SSSR.&amp;lt;/ref&amp;gt; — полиномиальный алгоритм, предназначенный для поиска [[Поиск максимального потока в транспортной сети| максимального потока в транспортной сети]]. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма &amp;lt;math&amp;gt;O(nm^2)&amp;lt;/math&amp;gt;. Достижение этой оценки стало возможно благодаря введению понятий блокирующего потока и слоистой сети. &lt;br /&gt;
&lt;br /&gt;
Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. &lt;br /&gt;
Алгоритм Диница схож с алгоритмом Эдмондса-Карпа&amp;lt;ref&amp;gt;Edmonds, Jack; Karp, Richard M. (1972). &amp;quot;Theoretical improvements in algorithmic efficiency for network flow problems&amp;quot;. Journal of the ACM. Association for Computing Machinery&amp;lt;/ref&amp;gt;, но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей (ведь именно такими путями и являются пути в блокирующем потоке слоистой сети).&lt;br /&gt;
&lt;br /&gt;
=== Математическое описание алгоритма ===&lt;br /&gt;
Математическая постановка задачи приведена в статье &amp;quot;[[Поиск максимального потока в транспортной сети]]&amp;quot;, мы будем использовать введённые в ней обозначения. &lt;br /&gt;
&lt;br /&gt;
Введём необходимые определения. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Остаточной сетью&#039;&#039;&#039; &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; по отношению к сети &amp;lt;math&amp;gt;G&amp;lt;/math&amp;gt; и некоторому потоку &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; в ней называется сеть, в которой каждому ребру &amp;lt;math&amp;gt;(u,v) \in G&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}&amp;lt;/math&amp;gt; и потоком &amp;lt;math&amp;gt;f_{uv}&amp;lt;/math&amp;gt;  соответствуют два ребра:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{uv}^R = c_{uv} - f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt; с пропускной способностью &amp;lt;math&amp;gt;c_{vu}^R = f_{uv}&amp;lt;/math&amp;gt;&lt;br /&gt;
Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt;, так и &amp;lt;math&amp;gt;(v,u)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Блокирующим потоком&#039;&#039;&#039; в данной сети называется такой поток, что любой путь из истока &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; в сток &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит насыщенное этим потоком ребро. Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.&lt;br /&gt;
&lt;br /&gt;
Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети &amp;lt;math&amp;gt;G^R&amp;lt;/math&amp;gt; не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Слоистая сеть&#039;&#039;&#039; для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока s до всех остальных вершин; назовём уровнем &amp;lt;math&amp;gt;{\rm level}[v]&amp;lt;/math&amp;gt; вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра &amp;lt;math&amp;gt;(u,v)&amp;lt;/math&amp;gt; исходной сети, которые ведут с одного уровня на какой-либо другой, более поздний, уровень, т.е. &amp;lt;math&amp;gt;{\rm level}[u] + 1 = {\rm level}[v]&amp;lt;/math&amp;gt; (разница расстояний не может превосходить единицы,  это следует из свойства кратчайших расстояний). Таким образом, удаляются все рёбра, расположенные целиком внутри уровней, а также рёбра, ведущие назад, к предыдущим уровням.&lt;br /&gt;
&lt;br /&gt;
Слоистая сеть ациклична. Кроме того, любой &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; путь в слоистой сети является кратчайшим путём в исходной сети.&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся &amp;lt;math&amp;gt;s-t&amp;lt;/math&amp;gt; пути.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Anastasy</name></author>
	</entry>
</feed>