Русская Википедия:Алгоритм Диница

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Алгоритм Диница — полиномиальный алгоритм для нахождения максимального потока в транспортной сети, предложенный в 1970 году советским (впоследствии израильским) математиком Ефимом Диницем. Временная сложность алгоритма составляет <math>O(|V|^2|E|)</math>. Получить такую оценку позволяет введение понятий вспомогательной сети и блокирующего (псевдомаксимального) потока. В сетях с единичными пропускными способностями существует более сильная оценка временной сложности: <math>O(|E||V|)</math>.

Описание

Пусть <math>G = (V,E,c,s,t)</math> — транспортная сеть, в которой <math>c(u,v)</math> и <math>f(u,v)</math> — соответственно пропускная способность и поток через ребро <math>(u,v)</math>.

Остаточная пропускная способность — отображение <math>c_f\colon V\times V \to \mathbb{R}^+</math> определённое как:
  1. Если <math>(u,v)\in E</math>,
    <math>c_f(u,v) = c(u,v) - f(u,v) </math>
    <math>c_f(v,u) = f(u,v)</math> В других источниках <math>c_f(u, v) = c(u, v) - f(u, v) + f(v, u)</math>
  2. <math>c_f(u,v) = 0</math> иначе.
Остаточная сеть — граф <math>G_f = (V, E_f, c_f|_{E_f}, s, t)</math>, где
<math>E_f = \{(u,v)\in V \times V \mid c_f(u,v) > 0\}</math>.
Дополняющий путь — <math>s-t</math> путь в остаточном графе <math>G_f</math>.
Пусть <math>\operatorname{dist}(v)</math> — длина кратчайшего пути из <math>s</math> в <math>v</math> в графе <math>G_f</math>. Тогда вспомогательная сеть графа <math>G_f</math> — граф <math>G_L = (V, E_L, c_f|_{E_L}, s,t)</math>, где
<math>E_L = \{(u,v)\in E_f \mid \operatorname{dist}(v) = \operatorname{dist}(u) + 1\}</math>.
Блокирующий поток — <math>s-t</math> поток <math>f</math> такой, что граф <math>G' = (V,E_L',c_f|_{E_L}, s, t)</math> с <math>E_L' = \{(u,v) \mid f(u,v) < c_f|_{E_L}(u,v)\}</math> не содержит <math>s-t</math> пути.

Алгоритм

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

Вход: Сеть <math>G = (V, E, c, s, t)</math>.
Выход: <math>s-t</math> поток <math>f</math> максимальной величины.
  1. Установить <math>f(e) = 0</math> для каждого <math>e\in E</math>.
  2. Создать <math>G_L</math> из <math>G_f</math> графа <math>G</math>. Если <math>\operatorname{dist}(t) = \infty</math>, остановиться и вывести <math>f</math>.
  3. Найти блокирующий поток <math>f'</math> в <math>G_L</math>.
  4. Дополнить поток <math>f</math> потоком <math>f'</math> и перейти к шагу 2.

Анализ

Можно показать, что каждый раз число в рёбер кратчайшем пути из источника в сток увеличивается хотя бы на единицу, поэтому в алгоритме не более <math>n-1</math> блокирующих потоков, где <math>n</math> — число вершин в сети. Вспомогательная сеть <math>G_L</math> может быть построена обходом в ширину за время <math>O(|V| + |E|)</math>, а блокирующий поток на каждом уровне графа может быть найден за время <math>O(|V||E|)</math>. Поэтому время работы алгоритма Диница есть <math>O(|V|) \cdot (O(|V|+|E|) + O(|V||E|)) = O(|V|^2 |E|)</math>.

Используя структуры данных, называемые динамические деревья, можно находить блокирующий поток на каждой фазе за время <math>O(|E| \log |V|)</math>, тогда время работы алгоритма Диница может быть улучшено до <math>O(|V||E| \log |V|)</math>.

Пример

Ниже приведена симуляция алгоритма Диница. Во вспомогательной сети <math>G_L</math> вершины с красными метками — значения <math>\operatorname{dist}(v)</math>. Блокирующий поток помечен синим.

<math>G</math> <math>G_f</math> <math>G_L</math>
1. Файл:Dinic algorithm G1.svg Файл:Dinic algorithm Gf1.svg Файл:Dinic algorithm GL1.svg

Блокирующий поток состоит из путей:

  1. <math>\{s, 1, 3, t\}</math> с 4 единицами потока,
  2. <math>\{s, 1, 4, t\}</math> с 6 единицами потока, и
  3. <math>\{s, 2, 4, t\}</math> с 4 единицами потока.

Следовательно, блокирующий поток содержит 14 единиц, а величина потока <math>|f|</math> равна 14. Заметим, что дополняющий путь имеет 3 ребра.

2. Файл:Dinic algorithm G2.svg Файл:Dinic algorithm Gf2.svg Файл:Dinic algorithm GL2.svg

Блокирующий поток состоит из путей:

  1. <math>\{s, 2, 4, 3, t\}</math> с 5 единицами потока.

Следовательно, блокирующий поток содержит 5 единиц, а величина потока <math>|f|</math> равна 14 + 5 = 19. Заметим, что дополняющий путь имеет 4 ребра.

3. Файл:Dinic algorithm G3.svg Файл:Dinic algorithm Gf3.svg Файл:Dinic algorithm GL3.svg

Сток <math>t</math> не достижим в сети <math>G_f</math>. Поэтому алгоритм останавливается и возвращает максимальный поток величины 19. Заметим, что в каждом блокирующем потоке количество рёбер в дополняющем пути увеличивается хотя бы на одно.

История

Алгоритм Диница был опубликован в 1970 г. бывшим советским учёным Ефимом Диницем, который сейчас является членом факультета вычислительной техники университета Бен-Гурион (Израиль), ранее, чем алгоритм Эдмондса — Карпа, который был опубликован в 1972, но создан ранее. Они независимо показали, что в алгоритме Форда — Фалкерсона в случае, если дополняющий путь является кратчайшим, длина дополняющего пути не уменьшается.

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

Временную сложность алгоритма можно уменьшить, если оптимизировать процесс поиска блокирующего потока. Для этого необходимо ввести понятие потенциала. Потенциал ребра <math>e \in E</math> есть <math>\operatorname{pot}(e) = c_f(e)</math>, а потенциал вершины <math>v \in V \setminus \{s, t\}</math> равен <math>\operatorname{pot}(v) = \min\{ \sum_{e \in \delta^+(v)} \operatorname{pot}(e), \sum_{e \in \delta^-(v)} \operatorname{pot}(e) \}</math>. По той же логике <math>\operatorname{pot}(s) = \sum_{e \in \delta^+(v)} \operatorname{pot}(e)</math>, а <math>\operatorname{pot}(t) = \sum_{e \in \delta^-(v)} \operatorname{pot}(e)</math> . Идея улучшения заключается в том, чтобы искать вершину с минимальным положительным потенциалом в вспомогательной сети и строить блокирующий поток через нее, используя очереди.

Вход: Сеть <math>G = (V, E, c, s, t)</math>.
Выход: <math>s-t</math> поток <math>f</math> максимальной величины.
  1. Установить <math>f(e) = 0</math> для каждого <math>e\in E</math>.
  2. Создать <math>G_L</math> из <math>G_f</math> графа <math>G</math>. Если <math>\operatorname{dist}(s, t) = \infty</math>, остановиться и вывести <math>f</math>.
  3. Установить <math>f'(e) = 0</math> для каждого <math>e\in E</math>.
  4. Определить потенциал каждой вершины.
  5. Пока существует вершина <math>v \in V</math> такая, что <math>\operatorname{pot}(v) > 0</math>:
    1. Определи поток <math>f</math> при помощи прямого распостранения из <math>v</math>.
    2. Определи поток <math>f</math> при помощи обратного распостранения из <math>v</math>.
    3. Дополни поток <math>f'</math> потоками <math>f</math> и <math>f'</math>.
  6. Дополнить поток <math>f</math> потоком <math>f'</math> и перейти к шагу 2.

Алгоритмы прямого и обратного распостранения служат поиску путей из <math>v</math> в <math>t</math> и из <math>s</math> в <math>v</math> соответственно. Пример работы алгоритма прямого распостранения с использованием очередей:

Вход: Вспомогательная сеть <math>G_L = (V, E_L, c_f|_{E_L}, s,t)</math>, вершина <math>v \in V</math> такая, что <math>\operatorname{pot}(v) > 0</math>.
Выход: Поток <math>f</math> из источника <math>s</math> в вершину <math>v</math>, являющийся частью блокирующего потока.
  1. Установить для всех <math>w \in V \setminus \{v\}</math>: <math>U(w) = 0</math>.
  2. Установить <math>U(v) = \operatorname{pot}(v)</math> и <math>\operatorname{pot}(v) = 0</math>.
  3. Добавить <math>v</math> в очередь <math>Q</math>.
  4. Пока очередь <math>Q</math> не пуста:
    1. Установить значение <math>v</math> равным последнему элементу очереди.
    2. Пока <math>U(v) > 0</math>:
      1. Для каждого ребра <math>e = (v, w) \in \delta^+ (v)</math>:
      2. <math>f(e) = \min\{ \operatorname{pot}(e), U(v) \}</math>.
      3. Обнови <math>U(v) = U(v) - f(e)</math>.
      4. Обнови <math>U(w) = U(w) + f(e)</math>.
      5. Установи <math>\operatorname{pot}(w) = \operatorname{pot}(w) - \operatorname{pot}(e)</math>.
      6. Если <math>w \neq t</math> и <math>U(w) = f(e)</math> удалить <math>w</math> из очереди <math>Q</math>.

В связи с тем, что в каждой итерации поиска блокирующего потока "насыщается" минимум одна вершина, он завершается за <math>|V| - 1</math> итераций в худшем случае, в каждой из которых рассматриваются максимум <math>|V|</math> вершин. Пусть <math>l_i</math> - количество "насыщенных" ребер в каждой <math>i</math>-той итерации поиска блокирующего потока. Тогда его асимптотическая сложность равна <math>\sum_{i=1}^{n-1} O(n + l_i) = O(n^2 + \sum_{i=1}^{n-1} l_i) = O(n^2 + m)</math>, где <math>n</math> - количество вершин и <math>m</math> - количество ребер в графе. Таким образом, асимптотическая сложность алгоритма Диница с распостранением равна <math>O(|V|^3)</math>, так как блокирующий поток может проходить максимум через <math>|V|</math> вершин.

Литература

Ссылки