Схема алгоритма Диница — различия между версиями
(→Определение слоистой сети) |
|||
Строка 11: | Строка 11: | ||
#Для каждого ребра <tex>(u,v)</tex> данной сети <tex>G</tex> зададим <tex>f(u,v) = 0</tex>. | #Для каждого ребра <tex>(u,v)</tex> данной сети <tex>G</tex> зададим <tex>f(u,v) = 0</tex>. | ||
#Построим вспомогательную сеть <tex>G_L</tex> из [[Дополняющая сеть, дополняющий путь|дополняющей сети]] <tex>G_f</tex> данного графа <tex>G</tex>. Если <tex>d[t] = \infty</tex>, остановиться и вывести <tex>f</tex>. | #Построим вспомогательную сеть <tex>G_L</tex> из [[Дополняющая сеть, дополняющий путь|дополняющей сети]] <tex>G_f</tex> данного графа <tex>G</tex>. Если <tex>d[t] = \infty</tex>, остановиться и вывести <tex>f</tex>. | ||
− | #[[Алгоритм поиска блокирующего потока в ациклической сети|Найдем блокирующий поток <tex>f'</tex> в <tex>G_L</tex> | + | #[[Алгоритм поиска блокирующего потока в ациклической сети|Найдем блокирующий поток <tex>f'</tex> в <tex>G_L</tex>]]. |
#Дополним поток <tex>f</tex> найденным потоком <tex>f'</tex> и перейдем к шагу 2. | #Дополним поток <tex>f</tex> найденным потоком <tex>f'</tex> и перейдем к шагу 2. | ||
Строка 27: | Строка 27: | ||
}} | }} | ||
Поскольку длина кратчайшего <tex>s \leadsto t</tex> пути не может превосходить <tex>n - 1</tex>, то, следовательно, алгоритм Диница совершает не более <tex>n - 1</tex> фазы. | Поскольку длина кратчайшего <tex>s \leadsto t</tex> пути не может превосходить <tex>n - 1</tex>, то, следовательно, алгоритм Диница совершает не более <tex>n - 1</tex> фазы. | ||
− | Таким образом, в зависимости от того, каким алгоритмом нахождения блокирующего потока мы пользовались, весь алгоритм Диница может выполняться за <tex>O(VE^2)</tex> или за <tex>O(V^2E)</tex>. Также возможно достичь асимптотики <tex>O(VE\log V)</tex>, если использовать динамические деревья Слетора и Тарьяна. | + | Таким образом, в зависимости от того, каким алгоритмом нахождения блокирующего потока мы пользовались, весь алгоритм Диница может выполняться за <tex>O(VE^2)</tex> или за <tex>O(V^2E)</tex>. Также возможно достичь асимптотики <tex>O(VE\log V)</tex>, если использовать [[Link-Cut_Tree | динамические деревья Слетора и Тарьяна]]. |
==Реализация== | ==Реализация== | ||
− | + | В данной реализации не строится вспомогательная сеть <tex>G_L</tex>, а вычисляются значения <tex>d[u]</tex> {{---}} кратчайших путей <tex>s \leadsto u</tex>. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | <tex>c[u][v]</tex> {{---}} пропускная способность ребра <tex>(uv)</tex>. | |
− | |||
− | |||
− | + | <tex>f[u][v]</tex> {{---}} поток через ребро <tex>(uv)</tex>. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | '''bool''' bfs(): | ||
+ | заполняем массив d значениями, равными -1 | ||
+ | Q.push(s) | ||
+ | '''while''' !Q.isEmpty | ||
+ | u = Q.pop() | ||
+ | '''for''' <tex>(uv) \in E(G)</tex> | ||
+ | '''if''' f[u][v] < c[u][v] and d[v] != -1 | ||
+ | d[v] = d[u] + 1 | ||
+ | Q.push(v) | ||
+ | '''return''' d[t] != -1 | ||
+ | |||
+ | <font color="darkgreen">//поиск блокирующего потока | ||
+ | //v - номер вершины | ||
+ | //cf - минимальная пропускная способность дополняющей сети на пройденном dfs пути</font> | ||
+ | '''int''' dfs(u, cf): | ||
+ | '''if''' u == t '''or''' cf == 0 | ||
+ | '''return''' cf | ||
+ | <font color="darkgreen">//p[u] - номер вершины на которой завершился обход для вершины u</font> | ||
+ | '''for''' v = p[u] '''to''' <tex>|V(G)| - 1</tex> | ||
+ | '''if''' d[v] == d[u] + 1 <font color="darkgreen">//это условие эквивалентно поиску во вспомогательной слоистой сети</font> | ||
+ | cfmin = dfs(v, min(cf, c[u][v] - f[u][v])) | ||
+ | f[u][v] += cfmin | ||
+ | f[v][u] -= cfmin | ||
+ | '''return''' cfmin | ||
+ | p[u]++ | ||
+ | '''return''' 0 | ||
+ | |||
+ | '''int''' findMaxFlow(): | ||
+ | maxFlow = 0 | ||
+ | '''while''' bfs() <font color="darkgreen">//пересчитываем d[i], заодно проверяем достижима ли t из s</font> | ||
+ | заполняем p нулями | ||
+ | flow = dfs(s, <tex>\infty</tex>) | ||
+ | '''while''' flow != 0 | ||
+ | maxFlow += flow | ||
+ | flow = dfs(s, <tex>\infty</tex>) | ||
+ | '''return''' maxFlow | ||
== Источники == | == Источники == | ||
*[http://www.e-maxx.ru/algo/dinic Алгоритм Диница на e-maxx.ru] | *[http://www.e-maxx.ru/algo/dinic Алгоритм Диница на e-maxx.ru] |
Версия 03:42, 18 декабря 2015
Содержание
Определение слоистой сети
Для начала определим для каждой вершины обходом в ширину).
В слоистую сеть включаем только те ребра исходной сети, для которых .
Полученная сеть ациклична, и любой путь в слоистой сети является кратчайшим путём в исходной, из свойств обхода в ширину.
В примере ребра, обозначенные пунктиром, не входят в слоистую сеть.
Слоистую сеть для графа G будем называть вспомогательной сетью.
Алгоритм
Пусть дана сеть. Требуется найти в этой сети поток из в максимальной величины.
Схема алгоритма
- Для каждого ребра данной сети зададим .
- Построим вспомогательную сеть дополняющей сети данного графа . Если , остановиться и вывести . из
- Найдем блокирующий поток . в
- Дополним поток найденным потоком и перейдем к шагу 2.
Корректность алгоритма
Покажем, что если алгоритм завершается, то на выходе у него получается поток именно максимальной величины.
В самом деле, предположим, что в какой-то момент во вспомогательной сети, построенной для остаточной сети, не удалось найти блокирующий поток. Это означает, что сток вообще не достижим во вспомогательной сети из истока. Но поскольку она содержит в себе все кратчайшие пути из истока в остаточной сети, это в свою очередь означает, что в остаточной сети нет пути из истока в сток. Следовательно, применяя теорему Форда-Фалкерсона, получаем, что текущий поток в самом деле максимален.
Асимптотика алгоритма
Теорема: |
Расстояние между истоком и стоком строго увеличивается после каждой фазы алгоритма, т.е. , где — значение, полученное на следующей фазе алгоритма. |
Доказательство: |
Проведём доказательство от противного. Пусть длина кратчайшего пути из истока в сток останется неизменной после очередной фазы алгоритма. Вспомогательная сеть строится по остаточной. Из предположения следует, что в остаточной сети будет содержаться только рёбра остаточной сети перед выполнением данной фазы, либо обратные к ним. Из этого получаем, что нашёлся | путь, который не содержит насыщенных рёбер и имеет ту же длину, что и кратчайший путь. Но этот путь должен был быть «заблокирован» блокирующим потоком, чего не произошло. Получили противоречие. Значит длина изменилась.
Поскольку длина кратчайшего динамические деревья Слетора и Тарьяна.
пути не может превосходить , то, следовательно, алгоритм Диница совершает не более фазы. Таким образом, в зависимости от того, каким алгоритмом нахождения блокирующего потока мы пользовались, весь алгоритм Диница может выполняться за или за . Также возможно достичь асимптотики , если использоватьРеализация
В данной реализации не строится вспомогательная сеть
, а вычисляются значения — кратчайших путей .— пропускная способность ребра .
— поток через ребро .
bool bfs():
заполняем массив d значениями, равными -1
Q.push(s)
while !Q.isEmpty
u = Q.pop()
for
if f[u][v] < c[u][v] and d[v] != -1
d[v] = d[u] + 1
Q.push(v)
return d[t] != -1
//поиск блокирующего потока
//v - номер вершины
//cf - минимальная пропускная способность дополняющей сети на пройденном dfs пути
int dfs(u, cf):
if u == t or cf == 0
return cf
//p[u] - номер вершины на которой завершился обход для вершины u
for v = p[u] to
if d[v] == d[u] + 1 //это условие эквивалентно поиску во вспомогательной слоистой сети
cfmin = dfs(v, min(cf, c[u][v] - f[u][v]))
f[u][v] += cfmin
f[v][u] -= cfmin
return cfmin
p[u]++
return 0
int findMaxFlow(): maxFlow = 0 while bfs() //пересчитываем d[i], заодно проверяем достижима ли t из s заполняем p нулями flow = dfs(s,) while flow != 0 maxFlow += flow flow = dfs(s, ) return maxFlow
Источники
- Алгоритм Диница на e-maxx.ru
- Алгоритм Диница на ru.wikipedia.org
- Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн Алгоритмы: построение и анализ — 2-е изд. — М.: «Вильямс», 2007. — С. 1296. — ISBN 5-8489-0857-4