Участник:Anastasy/Алгоритм Диница: различия между версиями

Материал из Алговики
Перейти к навигации Перейти к поиску
Строка 51: Строка 51:
 
* С помощью поиска в ширину слоистая сеть строится за время <math>O(m)</math>.
 
* С помощью поиска в ширину слоистая сеть строится за время <math>O(m)</math>.
 
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за <math>O(n + k)</math>, где <math>k</math> — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет <math>O(p)</math>, где <math>p</math> — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за <math>O(pn + \sum\limits_i{k_i})</math>. Учитывая, что все указатели в сумме прошли расстояние <math>O(m)</math>, это дает асимптотику <math>O(pn + pk)</math>. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается <math>O(mn)</math>.
 
* Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за <math>O(n + k)</math>, где <math>k</math> — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет <math>O(p)</math>, где <math>p</math> — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за <math>O(pn + \sum\limits_i{k_i})</math>. Учитывая, что все указатели в сумме прошли расстояние <math>O(m)</math>, это дает асимптотику <math>O(pn + pk)</math>. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается <math>O(mn)</math>.
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается<ref name="Dinic"/>, тогда так как длина кратчайшего <math>s-t</math> пути не может превосходить <math>n - 1</math>, то и количество фаз алгоритма не превосходит <math>n - 1</math>. Таким образом, весь алгоритм Диница выполняется за <math>O(n^2m)</math>.
+
* Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается<ref name="Dinic"/> (то есть <math>{\rm level'}[t] > {\rm level}[t]</math>, где <math>{\rm level'}[t]</math> — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего <math>s-t</math> пути не может превосходить <math>n - 1</math>, то и количество фаз алгоритма не превосходит <math>n - 1</math>. Таким образом, весь алгоритм Диница выполняется за <math>O(n^2m)</math>.
  
 
=== Информационный граф ===  
 
=== Информационный граф ===  

Версия 19:52, 9 ноября 2017

Алгоритм Диница

Автор: Киреева Анастасия, группа 416

1 Постановка задачи

1.1 Общее описание алгоритма

Алгоритм Диница [1] — полиномиальный алгоритм, предназначенный для поиска максимального потока в транспортной сети. Он был предложен советским учёным Ефимом Диницем в 1970 году. Временная сложность алгоритма [math]O(nm^2)[/math], где [math]m[/math] — число ребер, а [math]n[/math] — число вершин.

Основная идея алгоритма состоит в том, чтобы итеративно увеличивать величину потока вдоль некоторых путей из истока в сток. Алгоритм Диница схож с алгоритмом Эдмондса-Карпа[2], но основное отличие можно понимать так: на каждой итерации поток увеличивается не вдоль одного кратчайшего пути из истока в сток, а вдоль целого набора таких путей.

1.2 Математическое описание алгоритма

Математическая постановка задачи приведена в статье "Поиск максимального потока в транспортной сети", мы будем использовать введённые в ней обозначения.

Введём необходимые определения.

Остаточной сетью [math]G^R[/math] по отношению к сети [math]G=(V, E)[/math] и некоторому потоку [math]f[/math] в ней называется сеть, в которой каждому ребру [math](u,v) \in E[/math] с пропускной способностью [math]c_{uv}[/math] и потоком [math]f_{uv}[/math] соответствуют два ребра:

  • [math](u,v)[/math] с пропускной способностью [math]c_{uv}^R = c_{uv} - f_{uv}[/math]
  • [math](v,u)[/math] с пропускной способностью [math]c_{vu}^R = f_{uv}[/math]

Стоит отметить, что при таком определении в остаточной сети могут появляться кратные рёбра: если в исходной сети было как ребро [math](u,v)[/math], так и [math](v,u)[/math].

Блокирующим потоком в данной сети называется такой поток, что любой путь из истока [math]s[/math] в сток [math]t[/math] содержит насыщенное этим потоком ребро (то есть [math]c_{uv} = f_{uv}[/math] для некоторых [math]u,v \in V[/math]). Иными словами, в данной сети не найдётся такого пути из истока в сток, вдоль которого можно беспрепятственно увеличить поток.

Блокирующий поток не обязательно максимален. Согласно теореме Форда-Фалкерсона поток будет максимальным тогда и только тогда, когда в остаточной сети [math]G^R[/math] не найдётся [math]s-t[/math] пути; в блокирующем же потоке ничего не утверждается о существовании пути по рёбрам, появляющимся в остаточной сети.

Слоистая сеть для данной сети строится следующим образом. Сначала определяются длины кратчайших путей из истока [math]s[/math] до всех остальных вершин; назовём уровнем [math]{\rm level}[v][/math] вершины её расстояние от истока. Тогда в слоистую сеть включают все те рёбра [math](u,v)[/math] исходной сети, для которых верно [math]{\rm level}[u] + 1 = {\rm level}[v][/math].

Слоистая сеть ациклична. Кроме того, любой [math]s-t[/math] путь в слоистой сети является кратчайшим путём в исходной сети.

Алгоритм представляет собой несколько фаз. На каждой фазе сначала строится остаточная сеть, затем по отношению к ней строится слоистая сеть (обходом в ширину), а в ней ищется произвольный блокирующий поток. Найденный блокирующий поток прибавляется к текущему потоку, и на этом очередная итерация заканчивается. Алгоритм заканчивает свою работу, когда в построенной на некоторой итерации остаточной сети не найдётся [math]s-t[/math] пути.

1.3 Вычислительное ядро алгоритма

Наибольший объем вычислений приходится на:

1.4 Макроструктура алгоритма

Одним из важных шагов алгоритма является поиск блокирующего потока. Опишем, каким образом это можно сделать.

Ищем [math]s-t[/math] пути по одному обходом в глубину, пока такие пути находятся, при этом удаляем те ребра, вдоль которых невозможно дойти до стока. Для этого достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое неудалённое ребро, и увеличивать этот указатель в цикле внутри обхода в глубину.

1.5 Схема реализации последовательного алгоритма

Структуру алгоритма можно описать следующим образом:

  1. Для всех ребер [math](u, v) \in E[/math] сети [math]G[/math] присвоим [math]f_{uv}=0[/math].
  2. Построим остаточную сеть [math]G^R[/math] по отношению к сети [math]G[/math] и потоку [math]f[/math]. Затем строим слоистую сеть [math]G^L[/math] по отношению к сети [math]G^R[/math]. Если [math]{\rm level}[t]=∞[/math], алгоритм завершает работу и выводит поток [math]f[/math].
  3. Ищем блокирующий поток [math]f'[/math] в сети [math]G^R[/math]
  4. Прибавим [math]f'[/math] к потоку [math]f[/math] и переходим к шагу 2.

1.6 Последовательная сложность алгоритма

  • С помощью поиска в ширину слоистая сеть строится за время [math]O(m)[/math].
  • Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Таким образом, один запуск обхода в глубину работает за [math]O(n + k)[/math], где [math]k[/math] — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного блокирующего потока будет [math]O(p)[/math], где [math]p[/math] — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за [math]O(pn + \sum\limits_i{k_i})[/math]. Учитывая, что все указатели в сумме прошли расстояние [math]O(m)[/math], это дает асимптотику [math]O(pn + pk)[/math]. В худшем случае, когда блокирующий поток насыщает все рёбра, асимптотика получается [math]O(mn)[/math].
  • Можно показать, что после каждой итерации расстояние между стоком и истоком строго увеличивается[1] (то есть [math]{\rm level'}[t] \gt {\rm level}[t][/math], где [math]{\rm level'}[t][/math] — расстояние до стока, полученное на следующей итерации). Так как длина кратчайшего [math]s-t[/math] пути не может превосходить [math]n - 1[/math], то и количество фаз алгоритма не превосходит [math]n - 1[/math]. Таким образом, весь алгоритм Диница выполняется за [math]O(n^2m)[/math].

1.7 Информационный граф

1.8 Ресурс параллелизма алгоритма

1.9 Входные и выходные данные алгоритма

1.10 Свойства алгоритма

2 Программная реализация алгоритма

2.1 Особенности реализации последовательного алгоритма

2.2 Локальность данных и вычислений

2.3 Возможные способы и особенности параллельной реализации алгоритма

2.4 Масштабируемость алгоритма и его реализации

2.5 Динамические характеристики и эффективность реализации алгоритма

2.6 Выводы для классов архитектур

2.7 Существующие реализации алгоритма

3 Литература

  1. 1,0 1,1 Диниц, Е. А. “Алгоритм решения задачи о максимальном потоке в сети со степенной оценкой.” Доклады АН СССР 194, no. 4 (1970): 754–57
  2. Edmonds, Jack; Karp, Richard M. (1972). "Theoretical improvements in algorithmic efficiency for network flow problems". Journal of the ACM. Association for Computing Machinery