метод Форда – Фулкерсона или алгоритм Форда – Фулкерсона (FFA ) - это жадный алгоритм, который вычисляет максимальный поток в потоковой сети . Иногда его называют «методом», а не «алгоритмом», поскольку подход к поиску дополнительных путей в остаточном графе не полностью определен или определен в нескольких реализациях с разным временем выполнения. Он был опубликован в 1956 г. Л. Р. Форд младший и Д. Р. Фулкерсон. Имя «Форд – Фулкерсон» часто также используется для алгоритма Эдмондса – Карпа, который является полностью определенной реализацией метода Форда – Фулкерсона.
Идея алгоритма заключается в следующем: пока существует путь от источника (начальный узел) до приемника (конечный узел), с доступной емкостью на всех ребрах пути, мы отправляем поток по одной из дорожек. Потом находим другой путь и так далее. Путь с доступной емкостью называется расширяющимся путем.
Пусть быть графом, и для каждого ребра от u до v пусть будет емкость и быть потоком. Мы хотим найти максимальный поток от источника s до стока t. После каждого шага в алгоритме сохраняется следующее:
Ограничения емкости | Поток по ребру не может превышать его пропускную способность. | |
---|---|---|
Косая симметрия | Чистый поток от u к v должен быть противоположен чистому потоку от v к u (см. пример). | |
Сохранение потока | Чистый поток к узлу равен нулю, за исключением источника, который «производит» поток, и раковина, которая «потребляет» поток. | |
Значение (е) | Поток, выходящий из s, должен быть равен потоку, прибывающему в t. |
Это означает, что поток через сеть является допустимым потоком после каждого раунда в алгоритме. Мы определяем остаточную сеть как сеть с пропускной способностью и нет потока. Обратите внимание, что может случиться так, что поток из v в u разрешен в остаточной сети, но запрещен в исходной сети: if и , затем .
Алгоритм Форд – Фулкерсон
Путь на шаге 2 можно найти с помощью например, поиск в ширину (BFS) или поиск в глубину в . Если вы используете первый, алгоритм называется Эдмондс – Карп.
. Если на шаге 2 больше нет путей, s не сможет достичь t в остаточной сети. Если S - это набор узлов, достижимых s в остаточной сети, то общая пропускная способность в исходной сети ребер от S до остальной части V равна, с одной стороны, общему потоку, который мы нашли от s до t, и, с другой стороны, служит верхней границей для всех таких потоков. Это доказывает, что найденный нами поток максимален. См. также Теорема о максимальном потоке и минимальном разрезе.
Если график имеет несколько источников и приемников, мы действуем следующим образом: Предположим, что и . Добавьте новый источник с ребром от до каждого узла , с емкостью . И добавьте новую раковину с краем от каждого узла до , с емкостью . Затем примените алгоритм Форда – Фулкерсона.
Кроме того, если узел u имеет ограничение емкости , мы заменяем этот узел двумя узлами и край с емкостью . Затем примените алгоритм Форда – Фулкерсона.
При добавлении пути увеличения потока к потоку, уже установленному на графике, максимальный поток будет достигнут, когда на графике больше нет путей увеличения потока. Однако нет уверенности в том, что эта ситуация когда-либо будет достигнута, поэтому лучшее, что можно гарантировать, - это то, что ответ будет правильным, если алгоритм завершится. В случае, если алгоритм работает вечно, поток может даже не сходиться к максимальному потоку. Однако такая ситуация возникает только при нерациональных значениях расхода. Когда емкости являются целыми числами, время выполнения Форда – Фулкерсона ограничено (см. нотация большого O ), где - количество ребер в графе, а - максимальный поток в графе. Это связано с тем, что каждый дополнительный путь можно найти за времени и увеличивает поток на целое число не менее , с верхней границей .
Вариантом алгоритма Форда – Фулкерсона с гарантированным завершением и временем выполнения, не зависящим от максимального значения потока, является Алгоритм Эдмондса – Карпа, который выполняется за времени.
В следующем примере показаны первые шаги Форда – Фулкерсона в потоковой сети с 4 узлами, источником и раковина . Этот пример показывает наихудшее поведение алгоритма. На каждом этапе по сети передается только поток . Если бы вместо этого использовался поиск в ширину, потребовалось бы всего два шага.
Путь | Емкость | Результирующая потоковая сеть |
---|---|---|
Начальная потоковая сеть | ||
После 1998 года больше шагов... | ||
Конечная сеть потока |
Обратите внимание, как поток "отодвигается назад" "от до при нахождении пути .
Рассмотрим потоковую сеть, показанную справа, с источником , стоком , мощности ребер , и соответственно , и и пропускная способность всех других ребер некоторое целое число . Константа была выбрана так, что . Мы используем увеличивающие пути в соответствии со следующей таблицей, где , и .
Шаг | Путь расширения | Отправленный поток | Остаточная емкость | ||
---|---|---|---|---|---|
0 | |||||
1 | |||||
2 | |||||
3 | |||||
4 | |||||
5 |
Обратите внимание, что после шага 1, а также после шага 5 остаточные мощности ребер , и имеют форму , и , соответственно, для некоторых . Это означает, что мы можем использовать увеличивающие пути , , и бесконечно много раз, и остаточные мощности этих ребер всегда будут в одном и том же виде. Общий поток в сети после шага 5 равен . Если мы продолжим использовать дополняющие пути, как указано выше, общий поток сходится к . Однако обратите внимание, что существует поток значений , отправляя единиц поток вдоль , 1 единица потока вдоль и единиц потока вдоль . Следовательно, алгоритм никогда не завершается, и поток даже не сходится к максимальному потоку.
Другой пример без завершения, основанный на алгоритме Евклида, приведен Backman Huynh ( 2018), где также показано, что время работы алгоритма Форда-Фалкерсона в худшем случае в сети в порядковых числах равно .
импорт коллекций класс Graph (object): "" "Этот класс представляет ориентированный граф с использованием представления матрицы смежности." "" Def __init __ (self, graph): self.graph = graph # остаточный граф self.row = len (graph) def bfs (self, s, t, parent): "" "Возвращает истину, если существует путь от источника 's' к 't' в остаточном графе. Также заполняет родительский элемент для хранения пути." "" # Пометить все вершины как непосещенные посещенные = [False] * self.row # Создать очередь для BFS queue = collec tions.deque () # Пометить исходный узел как посещенный и поставить его в очередь queue.append (s)hibited [s] = True # Стандартный цикл BFS при очереди: u = queue.popleft () # Получить все смежные вершины удаленной вершины u # Если соседний объект не был посещен, отметьте его # посещенным и поставьте его в очередь для ind, val в enumerate (self.graph [u]): if (hibited [ind] == False) и (val>0): queue.append (ind) посещено [ind] = True parent [ind] = u # Если мы достигли приемника в BFS, начиная с источника, то возвращаем # true, иначе false return loaded [t] # Возвращает максимальный поток от s до t в данном графе def edmonds_karp (self, source,ink): # Этот массив заполняется BFS и хранит путь parent = [-1] * self.row max_flow = 0 # Первоначально нет потока # Увеличьте поток, пока есть - это путь от источника к приемнику, а self.bfs (источник, приемник, родитель): # Найти минимальную остаточную емкость ребер по # пути, заполненному BFS. Или мы можем сказать, что найти максимальный поток # по найденному пути. path_flow = float ("Inf") s = сток, в то время как s! = source: path_flow = min (path_flow, self.graph [parent [s]] [s]) s = parent [s] # Добавить поток пути к общему потоку max_flow + = path_flow # обновить остаточную пропускную способность ребер и обратных ребер # по пути v = сток, пока v! = source: u = parent [v] self.graph [u] [v] - = path_flow self.graph [v] [u] + = path_flow v = parent [v] return max_flow
Носитель, связанный с алгоритмом Форда-Фалкерсона на Wikimedia Commons