Вы находитесь на странице: 1из 5

Что же такое потоки и как их искать?

Историческая справка:
1954: американцы Лестер Форд и Делберт Фалкерсон доказали Теорему Форда-
Фалкерсона и описали алгоритм Форда-Фалкерсона

1970: израильский(советский) ученый Ефим Диниц описал алгоритм Диница и


алгоритм Эдмондса-Карпа

1972: американцы Джек Эдмондс и Ричард Карп независимо от Диница отписали


алгоритм Эдмондса-Карпа

1. Определения.
Потоки, Разрезы
Сеть - это ориентированный граф, в котором выбраны две вершины - исток (s) и сток
(t), и на ребрах которого определена пропускная способность c(e) >= 0.

Для удобства так же считается, что у каждого ребра есть его “двойник” - обратное
ребро e’. Удобно реализовывать изначально ребра так, что если c(e) > 0, то c(e’) = 0.

Дополняющий путь в сети - это путь из s в t, у которого все ребра имеют ненулевую
пропускную способность.

Поток - это функция на ребрах, удовлетворяющая следующим свойствам:


● f(e) <= c(e)
● f(e) = -f(e’)
● f(e_1) + … + f(e_k) = 0, где e_1…e_k - это все ребра(включая “двойники”),
выходящие из вершины v - верно для всех вершин v, кроме s и t
Величина потока - это сумма всех потоков на ребрах, ведущих из s. Обозначается как
|f|.
Максимальный поток - поток с максимальной величиной.

Остаточная сеть потока f - это граф с измененными пропускными способностями:


c_new(e) = c(e) - f(e).
Из первого свойства потока следует, что определение корректное.
Тут нужно понимать, что в остаточной сети у ребра-“двойника” пропускная
способность может стать больше нуля, это нормально.

Разрез сети - это разбиение всех вершин на два множества S и T, такое что s лежит в
S, а t лежит в T. Обозначается как (S, T).
Пропускная способность разреза - это сумма всех пропускных способностей ребер,
ведущих из S в T. Обозначается как c(S, T).
Поток через разрез - это сумма всех потоков через ребра, ведущих из S в T.
Обозначается как f(S, T)
Минимальный разрез - разрез с минимальной пропускной способностью.

2. Теорема Форда-Фалкерсона
Теорема Форда-Фалкерсона
Лемма: поток через разрез равен величине потока
f(S, T) = |f|
Доказательство: нужно аккуратно проверить:
f(S, T) = f(S, V) - f(S, S) = f(S, V) = f(S\s, V) + f(s, V) = f(s, V) = |f|

Теорема Форда-Фалкерсона
Следующие условия эквивалентны:
● f - максимальный поток
● в остаточной сети потока f нет дополняющего пути
● |f| = c(S, T) для некоторого разреза (S, T)
Доказательство:
1 => 2: от противного: если есть дополняющий путь, то прокинем по нему поток,
добавим его к f, получим новый, больший поток.
2 => 3: рассмотрим как S множество вершин, достижимых в остаточной сети из s по
ребрам ненулевой пропускной способности. t туда не входит, иначе есть дополняющий
путь. Рассмотрим разрез (S, T).
f(S, T) = c(S, T), потому что если для какого-то ребра между S и T это неправда, то в
остаточной сети по нему бы можно было пройти.
f(S, T) = |f| (Лемма)
Значит, c(S, T) = |f|
3 => 1: Заметим, что поток через разрез не больше, чем пропускная способность
разреза (легко проверить).
Для любых разрезов (S_1, T_1) и (S_2, T_2) выполняется:
f(S_1, T_1) = |f| = f(S_2, T_2) <= c(S_2, T_2)
Значит, все величины потоков не больше, чем все пропускные способности разрезов.
Значит, если где-то они совпали, то это максимальный поток и минимальный разрез
.
Хм, они как раз совпали, значит f - максимальный.

3. Алгоритм Форда-Фалкерсона
Алгоритм Форда-Фалкерсона
Задачу, которую мы все время будем хотеть решить - это задача о поиске
максимального потока в сети.

Алгоритм Форда-Фалкерсона:
Идея: Давайте сначала зададим нулевой поток: f = 0. Теперь будем просто итеративно
искать поиском в глубину любой дополняющий путь в остаточной сети потока f и
добавлять к потоку f поток минимальной пропускной способности на этом пути.
Делаем так, пока в остаточной сети есть дополняющий путь.
Почему корректен: Как только дополняющего пути не будет, по теореме Форда-
Фалкерсона будет достигнут максимальный поток.
Алгоритм достигнет максимального потока, если все пропускные способности -
натуральный числа. Если они вещественные, то есть пример сети, когда алгоритм
работает бесконечно долго, и величина потока даже не сходится к ответу.
Как писать: нужно итеративно(пока dfs находит путь) запускать dfs, искать им
дополняющий путь в остаточной сети и добавлять на этом пути поток минимальной
пропускной способности на этом пути.
Оценка времени работы: если пропускные способности целые, то O(MAX_C * (V +
E)), потому что MAX_C раз запускаем dfs, который работает O(V + E).
если они не целые, то бесконечно и не работает.

4. Алгоритм Эдмондса-Карпа
Алгоритм Эдмондса-Карпа
Но зачем искать любой путь?
Давайте искать кратчайший!

Алгоритм Эдмондса-Карпа:
Идея: Итерационно ищем с помощью поиска в ширину кратчайший по количеству
рёбер дополняющий путь в остаточной сети, пропускаем по нему поток. Делаем так,
пока есть дополняющий путь.
Почему корректен: Как только дополняющего пути не будет, поток - максимальный по
теореме Форда-Фалкерсона. Почему алгоритм завершит свою работу даже в
вещественном случае? См. далее в оценке времени работы.
Как писать: заменить в Форде-Фалкерсоне dfs на bfs.
Оценка времени работы: Всего будет O(VE) запусков bfs, поэтому алгоритм работает
за O(VE) * O(V + E) = O(V E^2). Докажем, почему запусков O(VE).
Лемма: Пусть d(v) - это длина кратчайшего по ребрам пути от s до v. d(v) в остаточной
сети не убывает в ходе алгоритма Эдмондса-Карпа.
Доказательство леммы: Пусть после увеличения потока f до f’ величина d(v)
уменьшилась. Возьмем вершину v с минимальным значением d(v), у которой d(v)
уменьшилось до d’(v). Рассмотрим в новой сети кратчайший путь от s до v.
Предпоследняя вершина на этом пути - это u. d’(u) + 1 = d’(v).
Тогда если в старой сети было ребро (u, v), тогда d(v) <= d(u) + 1 <= d’(u) + 1 = d’(v). Но
d(v) > d’(v), она же уменьшилось, противоречие.
А если в старой сети не было ребра (u, v)? Это значит, что было ребро (v, u), а
обратное появилось после увеличения потока f до f’, а значит кратчайший путь прошел
через v, а потом через u.
d(v) = d(u) - 1 <= d’(u) - 1 = d’(v) - 2, но d’(v) < d(v), противоречие.
Доказательство оценки: заметим, ребро может насытиться максимум V раз. После
каждого увеличение потока хотя бы одно ребро насыщается, значит запусков bfs всего
O(VE).
Почему ребро может насытиться максимум V раз? Потому что во время насыщения
ребра (u, v) d(u) + 1 = d(v), и в следующий раз оно насытится уже в обратную сторону,
то есть d’(u) - 1= d(v), а так как по лемме d(v) не уменьшается, то d(v) увеличилось на
два. d(v) может увеличиться на 2 не больше, чем V раз, значит и насытиться ребро
может максимум V раз.
Оценка доказана!

5. Алгоритм Диница
Блокирующий поток, Алгоритм Диница
Совершенно новый подход к поиску максимального потока - с использованием
блокирующего потока.

Слоистая сеть - разделение вершин сети на слои. В i-ом слое находятся вершины,
кратчайшее расстояние до которых от s равны i. В слоистой сети оставляются только
ребра из слоя i в слой i+1.
Блокирующий поток - такой поток в слоистой сети, что любой путь из s в t содержит
насыщенное этим потоком ребро.

Жадный алгоритм:
Идея: Будем итерационно строить слоистую сеть и проводить в ней блокирующий
поток. Как? Просто запуская dfs-ы и добавляя новые пути в сеть, пока они есть.
Почему корректен: Мы корректно строим блокирующий поток, потому что
останавливаемся, когда нет пути от s до t в слоистой сети. Мы корректно строим поток,
потому что когда мы не можем построить блокирующий поток, то в остаточной сети
нет пути от s до t, а значит по теореме Форда-Фалкерсона это максимальный поток.
Как писать: Много раз запускаем bfs, строим слоистую сеть, и для нее находим
блокирующий поток с помощью большого числа dfs-ов.
Оценка времени работы: Блокирующий поток находится за O(E^2), потому что это
O(E) запусков dfs, который работает за O(V + E). Почему O(E)? Потому что каждый dfs
насыщает хотя бы одно ребро в слоистой сети.
Докажем, что искать блокирующий поток нужно V раз. Почему? После каждого
добавления блокирующего потока в слоистой сети дополняющего пути в ней больше
нет, а значит кратчайшего пути длины |количество слоев|, а значит просто длина
кратчайшего пути от s до t увеличивается после каждого поиска блокирующего потока,
значит этих запусков не больше V.

Алгоритм Диница:
Идея: будем так же итерационно строить слоистую сеть и проводить в ней
блокирующий поток. Как? Теперь по-умному. Если dfs прошел по ребру, и не смог из
него достроить путь до t, то оно удаляется.
Почему корректен: По тому же самому.
Как писать: Что меняется по сравнению с жадным алгоритмом: в списке смежности
для каждой вершины нужно для каждой вершины хранить указатель на первое
неудаленное ребро. И в dfs-е начинать перебирать с него. И если, пройдя по этому
ребру, сток не достигнулся, то сдвигаем этот указатель на один.
Оценка времени работы: Надо доказать, что блокирующий поток строится за O(VE),
тогда общее время работы, учитывая V поисков блокирующего потока - это O(V^2 E)
Почему O(VE)? Потому что происходит E удалений ребер. А сам dfs, не учитывая
удалений, работает за O(V), запускается их все еще O(E). Вот отсюда O(VE).
6. Масштабирование
Масштабирование

Пусть все пропускные способности - целые и ограничены числом MAX_C.


Новая идея состоит в том, чтобы сначала пропускать потоки по большим ребрам, а
потом уже по маленьким.

Алгоритм Форда-Фалкерсона с масштабированием


Идея: Положим D = 2^[log2(MAX_C)]. Будем запускать Форда-Фалкерсона и
увеличивать максимальный поток в сети, пока есть дополняющие пути, но при этом
обрабатывать только ребра, у которых пропускная способность не меньше D. После
этого будем уменьшать D в два раза, пока он не станет равен 1.
Почему корректен: В конечном итоге при D = 1 это просто Форд-Фалкерсон.
Как писать: Почти так же, как Форда-Фалкерсона.
Оценка времени работы: Заметим, что если сейчас закончилась фаза с D = 2^k, то
максимальный поток в сети ограничен сверху значением |f| + 2^k * E. Почему? Потому
что в остаточной сети есть разрез (S, T) такой, что между S и T нет ребер с пропускной
способностью >=2^k. А значит его поток не превышает E * 2^k. А значит и
максимальный поток не превышает |f| + E * 2^k.
Тогда заметим, что в фазе с D = 2^(k-1) каждый дополняющий путь весит минимум
2^(k-1). Максимально добавить можно значит всего 2E дополняющих путей. Тогда dfs
запускается всего O(E log(MAX_C)) раз и суммарная асимптотика - O(E^2 log(MAX_C))

Алгоритм Диница с масштабированием


Идея: Та же самая. Положим D = 2^[log2(MAX_C)]. Будем запускать Диница и
увеличивать максимальный поток в сети, пока есть дополняющие пути, но при этом
обрабатывать только ребра, у которых пропускная способность не меньше D. После
этого будем уменьшать D в два раза, пока он не станет равен 1.
Почему корректен: В конечном итоге при D = 1 это просто Диниц.
Как писать: Почти так же, как Диница.
Оценка времени работы: Все еще заметим, что если сейчас закончилась фаза с D =
2^k, то максимальный поток в сети ограничен сверху значением |f| + 2^k * E.
Оценим число dfs-ов в каждой фазе.
Количество дополняющих путей все еще не больше 2Е, значит dfs(не учитывая
удаления) запусакает О(E) раз, работает он без удалений за O(V), отсюда O(VE).
Теперь оценим отдельно удаления. За одну фазу блокирующий поток ищется не более
чем V раз, в каждой фазе не более чем E удалений, тоже получаем O(VE).
Значит в каждой фазе Диниц работает за O(VE), суммарное время - O(V E log(MAX_C))