Алгоритм Эдмондса — Карпа Алгоритм Эдмондса — Карпа решает задачу нахождения максимального потока в транспортной сети. Алгоритм представляет собой частный случай метода Форда — Фалкерсона и работает за время в графе . Впервые был опубликован в 1970 году советским учёным Е. А. Диницом. Позже, в 1972 году, был независимо открыт Эдмондсом и Карпом.
Алгоритм
Алгоритм Эдмондса — Карпа — это вариант алгоритма Форда — Фалкерсона, при котором на каждом шаге выбирают кратчайший дополняющий путь из в в остаточной сети (полагая, что каждое ребро имеет единичную длину). Кратчайший путь находится поиском в ширину.
Описание
- Обнуляем все потоки. Остаточная сеть изначально совпадает с исходной сетью.
- В остаточной сети находим кратчайший путь из источника в сток. Если такого пути нет, останавливаемся.
- Пускаем через найденный путь (он называется увеличивающим путём или увеличивающей цепью) максимально возможный поток:
- На найденном пути в остаточной сети ищем ребро с минимальной пропускной способностью
.
- Для каждого ребра на найденном пути увеличиваем поток на
, а в противоположном ему — уменьшаем на .
- Модифицируем остаточную сеть. Для всех рёбер на найденном пути, а также для противоположных им рёбер, вычисляем новую пропускную способность. Если она стала ненулевой, добавляем ребро к остаточной сети, а если обнулилась, стираем его.
- Возвращаемся на шаг 2.
Чтобы найти кратчайший путь в графе, используем поиск в ширину:
- Создаём очередь вершин О. Вначале О состоит из единственной вершины s.
- Отмечаем вершину s как посещённую, без родителя, а все остальные как непосещённые.
- Пока очередь не пуста, выполняем следующие шаги:
- Удаляем первую в очереди вершину u.
- Для всех дуг (u, v), исходящих из вершины u, для которых вершина v ещё не посещена, выполняем следующие шаги:
- Отмечаем вершину v как посещённую, с родителем u.
- Добавляем вершину v в конец очереди.
- Если v = t, выходим из обоих циклов: мы нашли кратчайший путь.
- Если очередь пуста, возвращаем ответ, что пути нет вообще и останавливаемся.
- Если нет, идём от t к s, каждый раз переходя к родителю. Возвращаем путь в обратном порядке.
Сложность
В процессе работы алгоритм Эдмондса — Карпа будет находить каждый дополняющий путь за время . Ниже мы докажем, что общее число увеличений потока, выполняемое данным алгоритмом, составляет . Таким образом, сложность алгоритма Эдмондса — Карпа равна .
Доказательство
Назовём расстоянием от вершины x до вершины у длину кратчайшего пути от x до y в остаточной сети, измеряемую числом рёбер. Если такого пути нет, будем считать расстояние бесконечным. Будем говорить, что y приблизилась к x (отдалилась от x), если расстояние от x до y уменьшилось (увеличилось). Будем говорить, что y ближе к x (дальше от x), чем z, если расстояние от x до y меньше (больше), чем расстояние от x до z.
Лемма. В ходе работы алгоритма ни одна вершина никогда не приближается к источнику.
Доказательство. Пусть это не так, тогда при каком-то увеличении потока некоторые вершины приблизились к источнику. Назовём их неправильными. Выберем ту из неправильных вершин, которая после увеличения потока оказалась ближе всех к источнику (если таких больше одной, то любую из них). Обозначим выбранную вершину через v. Рассмотрим кратчайший путь от s до v. Обозначим предпоследнюю вершину на этом пути через u, таким образом, путь имеет вид . Поскольку u ближе к s, чем v, а v — ближайшая к s из неправильных вершин, то u — вершина правильная. Обозначив расстояния от s до u и v до и после увеличения потока соответственно через , , , , имеем:
![{\displaystyle d_{v}^{'}<d_{v}}](https://wikimedia.org/api/rest_v1/media/math/render/svg/4956a62a79b851c2f6c89eada1e4482cbcd7836d)
![{\displaystyle d_{u}^{'}\geq d_{u}}](https://wikimedia.org/api/rest_v1/media/math/render/svg/8c8541e76adc3f2bbb8cdfb6c72b44b24ec6bf9d)
,
откуда
![{\displaystyle d_{v}\geq d_{u}+2}](https://wikimedia.org/api/rest_v1/media/math/render/svg/058e5df4adbe65ebc7cf36f288291c4f5c0b8388)
Следовательно, до увеличения потока дуга (u, v) отсутствовала в остаточной сети. Чтобы оно появилось, увеличивающий путь должен был содержать дугу (v, u). Но в алгоритме Эдмондса — Карпа увеличивающий путь всегда кратчайший, следовательно,
,
что противоречит предыдущему неравенству. Значит, наше предположение было неверным. Лемма доказана.
Назовём критическим то из рёбер увеличивающего пути, у которого остаточная пропускная способность минимальна. Оценим, сколько раз некое ребро (u, v) может оказываться критическим. Пускай это произошло на итерации , а в следующий раз на итерации . Обозначая через расстояние от s до y на итерации t, имеем:
![{\displaystyle D_{v}(t_{1})=D_{u}(t_{1})+1}](https://wikimedia.org/api/rest_v1/media/math/render/svg/8a6a3778e9145bbdf5bac9dd0fac99f34e24657f)
![{\displaystyle D_{v}(t_{2})=D_{u}(t_{2})+1}](https://wikimedia.org/api/rest_v1/media/math/render/svg/821cce6a33bf6b1df4941152a609c73e14bdd093)
Заметим, что на итерации критическое ребро исчезает из остаточной сети. Чтобы к моменту итерации ребро (u, v) в ней вновь появилось, необходимо, чтобы на какой-то промежуточной итерации был выбран увеличивающий путь, содержащий ребро (v, u). Следовательно,
![{\displaystyle D_{u}(t_{3})=D_{v}(t_{3})+1}](https://wikimedia.org/api/rest_v1/media/math/render/svg/b5671083d2279dfcf0ba7d503ec6ae61b1e8b1ee)
Используя ранее доказанную лемму, получаем:
![{\displaystyle D_{v}(t_{2})=D_{u}(t_{2})+1\geq D_{u}(t_{3})+1=D_{v}(t_{3})+2\geq D_{v}(t_{1})+2}](https://wikimedia.org/api/rest_v1/media/math/render/svg/53e945a80e4c8dff8dd6ae7e22af6d7d26f709e9)
Поскольку изначально (иначе v = s, но ребро, ведущее в s, не может появиться на кратчайшем пути из s в t), и всегда, когда конечно, оно меньше |V| (кратчайший путь не содержит циклов, и, следовательно, содержит менее |V| рёбер), ребро может оказаться критическим не более раз. Поскольку каждый увеличивающий путь содержит хотя бы одно критическое ребро, а всего рёбер, которые могут когда-то стать критическими, (все рёбра исходной сети и им противоположные), то мы можем увеличить путь не более |Е|·|V| раз. Следовательно, число итераций не превышает O(|E|·|V|), что и требовалось доказать.
Пример
Пусть задана сеть с истоком в вершине и стоком в вершине . На рисунке парой обозначен поток по этому ребру и его пропускная способность.
Поиск в ширину
Опишем поиск в ширину на первом шаге.
- Очередь состоит из единственной вершины A. Посещена вершина A. Родителя нет.
- Очередь состоит (от начала к концу) из вершин B и D. Посещены вершины A, B, D. Вершины B, D имеют родителя А.
- Очередь состоит из вершин D и C. Посещены A, B, C, D. Вершины B, D имеют родителя А, вершина C — родителя B.
- Очередь состоит из вершин C, E, F. Посещены A, B, C, D, E, F. Вершины B, D имеют родителя А, вершина C — родителя B, вершины E, F — родителя D.
- Вершина C удаляется из очереди: рёбра из неё ведут только в уже посещённые вершины.
- Обнаруживается ребро (E,G) и цикл останавливается. В очереди вершины (F,G). Посещены все вершины. Вершины B,D имеют родителя А, вершина C — родителя B, вершины E,F — родителя D, вершина G — родителя E.
- Идём по родителя:
. Возвращаем пройденный путь в обратном порядке: .
Заметим, что в очередь последовательно добавляли вершины, достижимые из A ровно за 1 шаг, ровно за 2 шага, ровно за 3 шага. Кроме того, родителем каждой вершины является вершина, достижимая из A ровно на 1 шаг быстрее.
Основной алгоритм
Пропускная способность пути
|
Путь
|
|
![{\displaystyle \min(c_{f}(A,D),c_{f}(D,E),c_{f}(E,G))=}](https://wikimedia.org/api/rest_v1/media/math/render/svg/1fa2cfb55c6de3a7780c8873591a20b4100bb6c9)
![{\displaystyle \min(3-0,2-0,1-0)=}](https://wikimedia.org/api/rest_v1/media/math/render/svg/c4d59749f6379ea49894dc3981aa6c42250d297d)
![{\displaystyle \min(3,2,1)=1}](https://wikimedia.org/api/rest_v1/media/math/render/svg/927cf63543bdd3d2d265b893c07a05269446b364)
|
|
![](//upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Edmonds-Karp_flow_example_1.svg/300px-Edmonds-Karp_flow_example_1.svg.png) |
![{\displaystyle \min(c_{f}(A,D),c_{f}(D,F),c_{f}(F,G))=}](https://wikimedia.org/api/rest_v1/media/math/render/svg/be7aee74e750133ac52fc46e8d8db4a156f7bb8b)
![{\displaystyle \min(3-1,6-0,9-0)=}](https://wikimedia.org/api/rest_v1/media/math/render/svg/c35edb1f71ee1989d8b44c60a43c83589c5e57c2)
![{\displaystyle \min(2,6,9)=2}](https://wikimedia.org/api/rest_v1/media/math/render/svg/9ae0a8204d7d0c11ece9643ceab7042aca58c3d4)
|
|
![](//upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Edmonds-Karp_flow_example_2.svg/300px-Edmonds-Karp_flow_example_2.svg.png) |
![{\displaystyle \min(c_{f}(A,B),c_{f}(B,C),c_{f}(C,D),c_{f}(D,F),c_{f}(F,G))=}](https://wikimedia.org/api/rest_v1/media/math/render/svg/87503e3cd0961cc94640591dedbba7cb9d9a2176)
![{\displaystyle \min(3-0,4-0,1-0,6-2,9-2)=}](https://wikimedia.org/api/rest_v1/media/math/render/svg/85b11aa01dbf789ce10941d354ef29a8e408b3e6)
![{\displaystyle \min(3,4,1,4,7)=1}](https://wikimedia.org/api/rest_v1/media/math/render/svg/2fd3816138ff0b0e324c41a99a09f54db3af67e8)
|
|
![](//upload.wikimedia.org/wikipedia/commons/thumb/a/a5/Edmonds-Karp_flow_example_3.svg/300px-Edmonds-Karp_flow_example_3.svg.png) |
![{\displaystyle \min(c_{f}(A,B),c_{f}(B,C),c_{f}(C,E),c_{f}(E,D),c_{f}(D,F),c_{f}(F,G))=}](https://wikimedia.org/api/rest_v1/media/math/render/svg/717cfd8a15e57847e83fca9f6c0e3fa72caa1609)
![{\displaystyle \min(3-1,4-1,2-0,0--1,6-3,9-3)=}](https://wikimedia.org/api/rest_v1/media/math/render/svg/c060e1f50ac3f208143404830a58efd2edc5b163)
![{\displaystyle \min(2,3,2,1,3,6)=1}](https://wikimedia.org/api/rest_v1/media/math/render/svg/a53b9af7962536ff80e717fa6ec4bdb99f6940b1)
|
|
![](//upload.wikimedia.org/wikipedia/commons/thumb/b/bd/Edmonds-Karp_flow_example_4.svg/300px-Edmonds-Karp_flow_example_4.svg.png) |
Отметим, что в процессе выполнения алгоритма длины дополняющих путей (на рисунках обозначены красным) не убывают. Это свойство выполняется благодаря тому, что мы ищем кратчайший дополняющий путь.
Алгоритм Диница
Основная статья: Алгоритм Диница
Улучшенной версией алгоритма Эдмондса-Карпа является алгоритм Диница, требующий операций.
Назовём вспомогательной бесконтурной сетью графа G с источником s его подграф, содержащий только такие рёбра (u, v), для которых минимальное расстояние от s до v на единицу больше минимального расстояния от s до u.
Алгоритм Диница:
- Строим минимальную бесконтурную сеть остаточного графа.
- Пока в сети есть путь из s в t, выполнить следующие шаги:
- Находим кратчайший путь из s в t. Если его нет, выйти из цикла.
- На найденном пути в остаточной сети ищем ребро с минимальной пропускной способностью
.
- Для каждого ребра на найденном пути увеличиваем поток на
, а в противоположном ему — уменьшаем на .
- Удаляем все рёбра, достигшие насыщения.
- Удаляем все тупики (то есть вершины, кроме стока, откуда не выходит рёбер, и вершины, кроме источника, куда рёбер не входит) вместе со всеми инцидентными им рёбрами.
- Повторяем предыдущий шаг, пока есть что удалять.
- Если найденный поток ненулевой, добавляем его к общему потоку и возвращаемся на шаг 1.
Ссылки
Литература
- Томас Кормен и др. Алгоритмы: построение и анализ = INTRODUCTION TO ALGORITHMS. — 2-е изд. — М.: «Вильямс», 2006. — С. 1296. — ISBN 0-07-013151-1.
|