Алгоритм максимального потока Push-Relabel

Алгоритм в математической оптимизации

В математической оптимизации алгоритм push–relabel (альтернативно, preflow–push algorithm ) — это алгоритм для вычисления максимальных потоков в потоковой сети . Название «push–relabel» происходит от двух основных операций, используемых в алгоритме. На протяжении всего выполнения алгоритм поддерживает «предпоток» и постепенно преобразует его в максимальный поток, перемещая поток локально между соседними узлами с помощью операций push под руководством допустимой сети, поддерживаемой операциями relabel . Для сравнения, алгоритм Форда–Фалкерсона выполняет глобальные дополнения, которые отправляют поток по путям от источника до стока. [1]

Алгоритм push-relabel считается одним из самых эффективных алгоритмов максимального потока. Общий алгоритм имеет сильно полиномиальную временную сложность O ( V  2 E ) , которая асимптотически более эффективна, чем алгоритм Эдмондса–Карпа O ( VE  2 ) . [2] Конкретные варианты алгоритмов достигают еще более низкой временной сложности. Вариант, основанный на правиле выбора узла с наивысшей меткой, имеет временную сложность O ( V  2 E ) и обычно рассматривается как эталон для алгоритмов максимального потока. [3] [4] Субкубическая временная сложность O ( VE log( V  2 / E )) может быть достигнута с помощью динамических деревьев , [2] хотя на практике это менее эффективно. [ необходима цитата ]

Алгоритм push-relabel был расширен для вычисления потоков с минимальной стоимостью . [5] Идея меток расстояний привела к более эффективному алгоритму увеличивающегося пути, который, в свою очередь, может быть включен обратно в алгоритм push-relabel для создания варианта с еще более высокой эмпирической производительностью. [4] [6]

История

Концепция предпотока была первоначально разработана Александром В. Карзановым и опубликована в 1974 году в «Советских математических докладах» 15. Этот алгоритм предпотока также использовал операцию проталкивания; однако он использовал расстояния во вспомогательной сети для определения того, куда проталкивать поток, вместо системы маркировки. [2] [7]

Алгоритм push-relabel был разработан Эндрю В. Голдбергом и Робертом Тарьяном . Алгоритм был первоначально представлен в ноябре 1986 года в STOC '86: Proceedings of the eighteenth annual ACM symposium on Theory of computing, а затем официально в октябре 1988 года в качестве статьи в Journal of the ACM. Обе статьи подробно описывают общую форму алгоритма, завершающуюся за O ( V  2 E ), вместе с последовательной реализацией O ( V  3 ) , реализацией O ( VE  log( V  2 / E )) с использованием динамических деревьев и параллельной/распределенной реализацией. [2] [8] Как поясняется в [9] , Голдберг-Тарьян ввел метки расстояний, включив их в параллельный алгоритм максимального потока Йосси Шилоаха и Узи Вишкина . [10]

Концепции

Определения и обозначения

Позволять:

  • G = ( V , E ) сеть с функцией пропускной способности c : V × V Р {\displaystyle \mathbb {R} } ,
  • F = ( G , c , s , t ) — сеть потоков , где sV и tV — выбранные вершины источника и стока соответственно,
  • f  : V × V Р {\displaystyle \mathbb {R} } обозначает предпоток в F ,
  • x f  : V Р {\displaystyle \mathbb {R} } обозначим избыточную функцию относительно потока f , определяемую как x f ( u ) = Σ vV f ( v , u ) − Σ vV f ( u , v ) ,
  • c f  : V × V Р {\displaystyle \mathbb {R} } обозначает функцию остаточной пропускной способности относительно потока f , определяемую как c f  ( e ) = c ( e ) − f  ( e ) ,
  • E fE — ребра, где f < c ,

и

  • G f ( V , E f  ) обозначаютостаточную сеть Gотносительно потока f .

Алгоритм push–relabel использует неотрицательную целочисленную допустимую функцию маркировки , которая использует метки расстояний или высоты на узлах для определения того, какие дуги следует выбрать для операции push. Эта функция маркировки обозначается как 𝓁 : V Н {\displaystyle \mathbb {N} } . Эта функция должна удовлетворять следующим условиям, чтобы считаться допустимой:

Действительная маркировка :
𝓁( u ) ≤ 𝓁( v ) + 1 для всех ( u , v ) ∈ E f
Исходное состояние :
𝓁( s ) = |  V  |
Сохранение раковины :
𝓁( т ) = 0

В алгоритме значения меток s и t фиксированы. 𝓁( u ) — нижняя граница невзвешенного расстояния от u до t в G f ,   если t достижим из u . Если u был отключен от t , то 𝓁( u ) − |  V  | — нижняя граница невзвешенного расстояния от u до s . В результате, если существует допустимая функция маркировки, в G f нет путей s - t ,   поскольку ни один из таких путей не может быть длиннее V  | − 1 .

Дуга ( u , v ) ∈ E f   называется допустимой, если 𝓁( u ) = 𝓁( v ) + 1 . Допустимая сеть f ( V , f  ) состоит из множества дуг eE f   , которые являются допустимыми. Допустимая сеть ациклична.

Для фиксированного потока f вершина v ∉ { s, t } называется активной , если она имеет положительный избыток относительно f , т. е. x f ( u ) > 0 .

Операции

Инициализация

Алгоритм начинается с создания остаточного графа, инициализации значений предпотока нулем и выполнения набора насыщающих операций push на остаточных дугах ( s , v ), выходящих из источника, где vV \ { s } . Аналогично метки инициализируются таким образом, что метка в источнике представляет собой количество узлов в графе, 𝓁( s ) = |  V  | , а всем остальным узлам присваивается метка, равная нулю. После завершения инициализации алгоритм многократно выполняет операции push или relabel в отношении активных узлов до тех пор, пока не будет выполнена ни одна применимая операция.

Толкать

Операция push применяется к допустимой внешней дуге ( u , v ) активного узла u в G f . Она перемещает min{ x f ( u ), c ​​f ( u , v )} единиц потока из u в v .

нажимаем (u, v): утверждать x f [u] > 0 и 𝓁[u] == 𝓁[v] + 1 Δ = min(x f [u], c[u][v] - f[u][v]) ф[у][в] += Δ f[v][u] -= Δ х ф [и] -= Δ х ф [в] += Δ

Операция push, которая заставляет f  ( u , v ) достичь c ( u , v ) , называется насыщающим push , поскольку она использует всю доступную емкость остаточной дуги. В противном случае весь избыток в узле проталкивается через остаточную дугу. Это называется ненасыщающим push или ненасыщающим push .

Перемаркировать

Операция перемаркировки применяется к активному узлу u, который не является ни источником, ни стоком без каких-либо допустимых исходящих дуг в G f . Она изменяет 𝓁( u ) на минимальное значение, при котором создается допустимая исходящая дуга. Обратите внимание, что это всегда увеличивает 𝓁( u ) и никогда не создает крутую дугу, которая является дугой ( u , v ) такой, что c f  ( u , v ) > 0 , и 𝓁( u ) > 𝓁( v ) + 1 .

переименовать(u): утверждают x f [u] > 0 и 𝓁[u] <= 𝓁[v] для всех v таких, что c f [u][v] > 0 𝓁[u] = 1 + min(𝓁[v] для всех v таких, что c f [u][v] > 0)

Эффекты push и relabel

После операции push или перемаркировки 𝓁 остается допустимой функцией маркировки по отношению к f .

Для операции push на допустимой дуге ( u , v ) она может добавить дугу ( v , u ) к E f , где 𝓁( v ) = 𝓁( u ) − 1 ≤ 𝓁( u ) + 1 ; она также может удалить дугу ( u , v ) из E f , где она эффективно снимает ограничение 𝓁( u ) ≤ 𝓁( v ) + 1 .

Чтобы увидеть, что операция перемаркировки на узле u сохраняет действительность 𝓁( u ) , обратите внимание, что это тривиально гарантируется определением для исходящих дуг u в G f . Для входящих дуг u в G f увеличившееся 𝓁( u ) может только менее строго удовлетворять ограничениям, но не нарушать их.

Общий алгоритм push-relabel

Алгоритм generic push–relabel используется только в качестве доказательства концепции и не содержит подробностей реализации о том, как выбрать активный узел для операций push и relabel. Эта общая версия алгоритма завершится за O ( V 2 E ) .

Так как 𝓁( s ) = |  V  | , 𝓁( t ) = 0 , и нет путей длиннее V  | − 1 в G f , для того, чтобы 𝓁( s ) удовлетворял допустимому условию маркировки , s должен быть отключен от t . При инициализации алгоритм выполняет это требование, создавая предварительный поток f , который насыщает все исходящие дуги s , после чего 𝓁( v ) = 0 тривиально допустимо для всех vV \ { s , t } . После инициализации алгоритм многократно выполняет применимую операцию push или relabel до тех пор, пока такие операции не будут применены, после чего предварительный поток преобразуется в максимальный поток.

generic-push-relabel(G, c, s, t): создать предварительный поток f, который насыщает все исходящие дуги s пусть 𝓁[s] = |V| пусть 𝓁[v] = 0 для всех v ∈ V \ {s}, пока есть применимая операция push или relabel do выполнить операцию

Корректность

Алгоритм поддерживает условие, что 𝓁 является допустимой маркировкой во время его выполнения. Это можно доказать, изучив эффекты операций push и relabel на функцию метки 𝓁 . Операция relabel увеличивает значение метки на соответствующий минимум плюс один, который всегда будет удовлетворять ограничению 𝓁( u ) ≤ 𝓁( v ) + 1. Операция push может отправить поток из u в v, если 𝓁( u ) = 𝓁( v ) + 1 . Это может добавить ( v , u ) к G f  и может удалить ( u , v ) из G f  . Добавление ( v , u ) к G f  не повлияет на допустимую маркировку, поскольку 𝓁( v ) = 𝓁( u ) − 1 . Удаление ( u , v ) из Gf  удаляет соответствующее ограничение, поскольку допустимое свойство маркировки 𝓁 ( u ) ≤ 𝓁( v ) + 1 применяется только к остаточным дугам в Gf .  [8]

Если существует предпоток f и допустимая маркировка 𝓁 для f , то в остаточном графе G f нет увеличивающего пути от s до t . Это можно доказать от противного на основе неравенств, которые возникают в функции маркировки при предположении, что увеличивающий путь существует. Если алгоритм завершается, то все узлы в V \ { s , t } неактивны. Это означает, что все vV \ { s , t } не имеют избыточного потока, и без избытка предпоток f подчиняется ограничению сохранения потока и может считаться нормальным потоком. Этот поток является максимальным потоком согласно теореме о максимальном потоке и минимальном разрезе , поскольку нет увеличивающего пути от s до t . [8] 

Таким образом, по завершении работы алгоритм вернет максимальный поток.

Сложность времени

Чтобы ограничить временную сложность алгоритма, мы должны проанализировать количество операций push и relabel, которые происходят в основном цикле. Количество операций relabel, saturating push и nonsaturating push анализируется отдельно.

В алгоритме операция перемаркировки может быть выполнена не более (2|  V  | − 1)(|  V  | − 2) < 2|  V  | 2 раз. Это связано с тем, что значение маркировки 𝓁( u ) для любого узла u никогда не может уменьшиться, а максимальное значение метки не более 2|  V  | − 1 для всех узлов. Это означает, что операция перемаркировки потенциально может быть выполнена 2|  V  | − 1 раз для всех узлов V \ { s , t } (т. е. V  | − 2 ). Это приводит к ограничению O ( V  2 ) для операции перемаркировки.

Каждый насыщающий push на допустимой дуге ( u , v ) удаляет дугу из G f  . Чтобы дуга была повторно вставлена ​​в G f  для другого насыщающего push, v сначала должна быть перемаркирована, затем push на дуге ( v , u ) , затем u должна быть перемаркирована. В процессе 𝓁( u ) увеличивается как минимум на два. Следовательно, существует O ( V ) насыщающих push на ( u , v ) , а общее количество насыщающих push не превышает 2|  V  ||  E  | . Это приводит к временному ограничению O ( VE ) для операций насыщающего push.

Ограничение числа ненасыщающих push может быть достигнуто с помощью потенциального аргумента . Мы используем потенциальную функцию Φ = Σ [ uVx f  ( u ) > 0] 𝓁( u ) (т. е. Φ является суммой меток всех активных узлов). Очевидно, что Φ изначально равно 0 и остается неотрицательным на протяжении всего выполнения алгоритма. Как перемаркировка, так и насыщающие push могут увеличить Φ . Однако значение Φ должно быть равно 0 при завершении, поскольку в конце выполнения алгоритма не может остаться никаких активных узлов. Это означает, что в ходе выполнения алгоритма ненасыщающие push-операции должны составлять разницу между операциями relabel и saturating push, чтобы Φ завершилось со значением 0. Операция relabel может увеличить Φ не более чем на (2|  V  | − 1)(|  V  | − 2) . Насыщающий push на ( u , v ) активирует v , если он был неактивен до push, увеличивая Φ не более чем на 2|  V  | − 1 . Следовательно, общий вклад всех операций saturating push в Φ не более чем на (2|  V  | − 1)(2|  V  ||  E  |) . Ненасыщающий push на ( u , v ) всегда деактивирует u , но он также может активировать v, как в насыщающем push. В результате он уменьшает Φ по крайней мере на 𝓁( u ) − 𝓁( v ) = 1 . Поскольку перемаркировки и насыщающие push увеличивают Φ , общее количество ненасыщающих push должно составлять разницу (2|  V  | − 1)(|  V  | − 2) + (2|  V  | − 1)(2|  V  ||  E  |) ≤ 4|  V  | 2E  | . Это приводит к временному ограничению O ( V  2 E ) для ненасыщающих операций push.

В целом, алгоритм выполняет O ( V  2 ) перемаркировок, O ( VE ) насыщающих push-ов и O ( V  2 E ) ненасыщающих push-ов. Структуры данных могут быть спроектированы для выбора и выполнения соответствующей операции за время O (1) . Таким образом, временная сложность алгоритма составляет O ( V  2 E ) . [1] [8]

Пример

Ниже приведен пример выполнения универсального алгоритма push-relabel, определенного выше, на следующей простой схеме сетевого потока.

В примере значения h и e обозначают метку 𝓁 и избыток x f  , соответственно, узла во время выполнения алгоритма. Каждый остаточный граф в примере содержит только остаточные дуги с емкостью больше нуля. Каждый остаточный граф может содержать несколько итераций цикла выполнения операции .

Операция(ы) алгоритмаОстаточный график
Инициализируйте остаточный график, установив предварительный поток на значения 0 и инициализировав маркировку.Шаг 1
Начальный насыщающий толчок выполняется по всем дугам предпотока из источника, s .Шаг 2
Узел a перемаркирован, чтобы направить его избыточный поток в сторону стока t .

Избыток в точке a затем перемещается в точку b, а затем в точку d двумя последовательными насыщающими перемещениями; в результате чего в точке a все еще остается некоторый избыток.

Шаг 3
И снова a перемаркируется, чтобы переместить его избыток вдоль его последнего оставшегося положительного остатка (т.е. переместить избыток обратно в s ).

Затем узел a удаляется из набора активных узлов.

Шаг 4
Переименуем b , а затем переместим его избыток в t и c .Шаг 5
Переименуйте c и переместите его избыток в d .Шаг 6
Переименуйте d и затем переместите его избыток в t .Шаг 7
В результате узел b остается единственным активным узлом, но он не может направить свой избыточный поток в сторону стока.

Переименуем b , а затем протолкнем его избыток к источнику s через узел a .

Шаг 8
Отодвиньте последний излишек назад к источнику, s .

Активных узлов не осталось. Алгоритм завершается и возвращает максимальный поток графа (как показано выше).

Шаг 9

Пример (но с начальным потоком 0) можно запустить здесь в интерактивном режиме.

Практические реализации

В то время как общий алгоритм push–relabel имеет временную сложность O ( V  2 E ) , эффективные реализации достигают O ( V  3 ) или более низкой временной сложности за счет применения соответствующих правил при выборе применимых операций push и relabel. Эмпирическая производительность может быть дополнительно улучшена с помощью эвристики.

Структура данных «ток-дуга» и операция разряда

Структура данных "current-arc" представляет собой механизм посещения входящих и исходящих соседей узла в потоковой сети в статическом кольцевом порядке. Если для узла создается односвязный список соседей, структура данных может быть такой же простой, как указатель на список, который проходит по списку и возвращается к началу, когда он заканчивается.

На основе структуры данных «текущая дуга» можно определить операцию разряда. Операция разряда применяется к активному узлу и многократно выталкивает поток из узла, пока он не станет неактивным, перемаркируя его по мере необходимости для создания допустимых дуг в процессе.

discharge(u): while x f [u] > 0 do  if current-arc[u] вышел за пределы neighbors[u] then переименовать(u) перемотка тока-дуги[u] иначе  пусть (u, v) = current-arc[u] если (u, v) допустимо , то нажимаем (u, v) пусть current-arc[u] указывает на следующего соседа u

Поиск следующего допустимого ребра для перемещения имеет амортизированную сложность . Указатель текущей дуги перемещается к следующему соседу только тогда, когда ребро к текущему соседу насыщено или недопустимо, и ни одно из этих двух свойств не может измениться, пока активный узел не будет перемаркирован. Таким образом, когда указатель уходит, допустимых ненасыщенных ребер нет, и нам приходится перемаркировать активный узел , поэтому перемещение указателя оплачивается операцией перемаркировки. [8] О ( 1 ) {\displaystyle O(1)} ты {\displaystyle u} ты {\displaystyle u} О ( В ) {\displaystyle O(V)} О ( В ) {\displaystyle O(V)}

Правила выбора активных узлов

Определение операции разрядки сводит алгоритм push–relabel к многократному выбору активного узла для разрядки. В зависимости от правила выбора алгоритм демонстрирует различную временную сложность. Для краткости мы игнорируем s и t при ссылке на узлы в следующем обсуждении.

Правило выбора FIFO

Алгоритм FIFO push–relabel [2] организует активные узлы в очередь. Начальные активные узлы могут быть вставлены в произвольном порядке. Алгоритм всегда удаляет узел в начале очереди для выгрузки. Всякий раз, когда неактивный узел становится активным, он добавляется в конец очереди.

Алгоритм имеет временную сложность O ( V  3 ) .

Правило выбора «переместить метку вперед»

Алгоритм relabel-to-front push–relabel [1] организует все узлы в связанный список и сохраняет инвариант, что список топологически отсортирован относительно допустимой сети. Алгоритм сканирует список от начала до конца и выполняет операцию разрядки на текущем узле, если он активен. Если узел перемаркирован, он перемещается в начало списка, и сканирование перезапускается с начала.

Алгоритм также имеет временную сложность O ( V  3 ) .

Правило выбора наивысшей метки

Алгоритм push-relabel с наивысшей меткой [11] организует все узлы в сегменты, индексированные по их меткам. Алгоритм всегда выбирает активный узел с наибольшей меткой для выгрузки.

Алгоритм имеет временную сложность O ( V  2 E ) . Если вместо этого использовать правило выбора наименьшей метки, временная сложность становится O ( V  2 E ) . [3]

Методы внедрения

Хотя в описании общего алгоритма push-relabel выше 𝓁( u ) устанавливается равным нулю для каждого узла u, кроме s и t в начале, предпочтительнее выполнить обратный поиск в ширину от t для вычисления точных меток. [2]

Алгоритм обычно разделяется на две фазы. Фаза 1 вычисляет максимальный предварительный поток, выгружая только активные узлы, метки которых ниже n . Фаза 2 преобразует максимальный предварительный поток в максимальный поток, возвращая избыточный поток, который не может достичь t , в s . Можно показать, что фаза 2 имеет временную сложность O ( VE ) независимо от порядка операций push и relabel и, следовательно, доминирует над фазой 1. В качестве альтернативы, ее можно реализовать с помощью разложения потока. [9]

Эвристики имеют решающее значение для улучшения эмпирической производительности алгоритма. [12] Две наиболее часто используемые эвристики — это эвристика пробелов и эвристика глобальной перемаркировки. [2] [13] Эвристика пробелов обнаруживает пробелы в функции маркировки. Если есть метка 0 < 𝓁 ' < |  V  |, для которой нет узла u такого, что 𝓁( u ) = 𝓁 ' , то любой узел u с 𝓁 ' < 𝓁( u ) < |  V  | был отключен от t и может быть немедленно перемаркирован в (|  V  | + 1) . Эвристика глобальной перемаркировки периодически выполняет обратный поиск в ширину из t в G f  для вычисления точных меток узлов. Обе эвристики пропускают бесполезные операции перемаркировки, которые являются узким местом алгоритма и способствуют неэффективности динамических деревьев. [4]

Примеры реализаций

Реализация на языке С
#include <stdlib.h> #include <stdio.h>  #define УЗЛЫ 6 #define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) #define INFINITE 10000000void push ( const int * const * C , int ** F , int * избыток , int u , int v ) { int send = MIN ( избыток [ u ], C [ u ][ v ] - F [ u ][ v ]); F [ u ][ v ] += отправить ; F [ v ][ u ] -= отправить ; избыток [ u ] -= отправить ; избыток [ v ] += отправить ; }                                   void relabel ( const int * const * C , const int * const * F , int * height , int u ) { int v ; int min_height = INFINITE ; for ( v = 0 ; v < NODES ; v ++ ) { if ( C [ u ][ v ] - F [ u ][ v ] > 0 ) { min_height = MIN ( min_height , height [ v ]); height [ u ] = min_height + 1 ; } } } ;                                                  void discharge ( const int * const * C , int ** F , int * избыток , int * высота , int * видно , int u ) { while ( избыток [ u ] > 0 ) { if ( видно [ u ] < УЗЛЫ ) { int v = видно [ u ]; if (( C [ u ][ v ] - F [ u ][ v ] > 0 ) && ( высота [ u ] > высота [ v ])) { push ( C , F , избыток , u , v ); } else { видно [ u ] += 1 ; } } else { relabel ( C , F , высота , u ); видно [ u ] = 0 ; } } }                                                                   void moveToFront ( int i , int * A ) { int temp = A [ i ]; int n ; for ( n = i ; n > 0 ; n -- ) { A [ n ] = A [ n -1 ]; } A [ 0 ] = temp ; }                           int pushRelabel ( const int * const * C , int ** F , int source , int sink ) { int * избыток , * высота , * список , * увиденное , i , p ;                      избыток = ( int * ) calloc ( УЗЛЫ , sizeof ( int )); высота = ( int * ) calloc ( УЗЛЫ , sizeof ( int )); видно = ( int * ) calloc ( УЗЛЫ , sizeof ( int ));                  список = ( целое число * ) calloc (( УЗЛЫ -2 ), sizeof ( целое число ));      для ( i = 0 , p = 0 ; i < УЗЛЫ ; i ++ ) { если (( i != источник ) && ( i != приемник )) { список [ p ] = i ; p ++ ; } }                          высота [ источник ] = УЗЛЫ ; избыток [ источник ] = БЕСКОНЕЧНОСТЬ ; для ( i = 0 ; i < УЗЛЫ ; i ++ ) push ( C , F , избыток , источник , i );                   p = 0 ; while ( p < NODES - 2 ) { int u = list [ p ]; int old_height = height [ u ]; discharge ( C , F , extra , height , seen , u ); if ( height [ u ] > old_height ) { moveToFront ( p , list ); p = 0 ; } else { p += 1 ; } } int maxflow = 0 ; for ( i = 0 ; i < NODES ; i ++ ) maxflow += F [ source ][ i ];                                                         бесплатно ( список ); свободный ( видимый ); свободный ( высота ); свободный ( избыток );   вернуть максимальный поток ; } void printMatrix ( const int * const * M ) { int i , j ; for ( i = 0 ; i < УЗЛЫ ; i ++ ) { for ( j = 0 ; j < УЗЛЫ ; j ++ ) printf ( "%d \t " , M [ i ][ j ]); printf ( " \n " ); } }                              int main ( void ) { int ** flow , ** capacitys , i ; flow = ( int ** ) calloc ( NODES , sizeof ( int * )); capacity = ( int ** ) calloc ( NODES , sizeof ( int * )); for ( i = 0 ; i < NODES ; i ++ ) { flow [ i ] = ( int * ) calloc ( NODES , sizeof ( int )); capacity [ i ] = ( int * ) calloc ( NODES , sizeof ( int )); }                                         // Пример графа мощности [ 0 ][ 1 ] = 2 ; мощности [ 0 ][ 2 ] = 9 ; мощности [ 1 ][ 2 ] = 1 ; мощности [ 1 ][ 3 ] = 0 ; мощности [ 1 ][ 4 ] = 0 ; мощности [ 2 ][ 4 ] = 7 ; мощности [ 3 ][ 5 ] = 7 ; мощности [ 4 ][ 5 ] = 4 ;                         printf ( "Вместимость: \n " ); printMatrix ( емкости );  printf ( "Максимальный поток: \n %d \n " , pushRelabel ( емкости , поток , 0 , 5 ));     printf ( "Потоки: \n " ); printMatrix ( flow );  вернуть 0 ; } 
Реализация Python
def  relabel_to_front ( C ,  source :  int ,  sink :  int )  ->  int :  n  =  len ( C )  # C - матрица пропускной способности  F  =  [[ 0 ]  *  n  for  _  in  range ( n )]  # остаточная пропускная способность от u до v равна C[u][v] - F[u][v] height  =  [ 0 ]  *  n  # высота узла  избыток  =  [ 0 ]  *  n  # поток в узел минус поток из узла  виден  =  [ 0 ]  *  n  # соседи видны с момента последней перемаркировки  # узел "очередь"  nodelist  =  [ i  for  i  in  range ( n )  if  i  !=  source  and  i  !=  sink ] def  push ( u ,  v ):  send  =  min ( excess [ u ],  C [ u ][ v ]  -  F [ u ][ v ])  F [ u ][ v ]  +=  send  F [ v ][ u ]  -=  send  extra [ u ]  -=  send  extra [ v ]  +=  send def  relabel ( u ):  # Найти наименьшую новую высоту, делающую возможным толчок,  # если такой толчок вообще возможен.  min_height  =   для  v  в  диапазоне ( n ):  если  C [ u ][ v ]  -  F [ u ][ v ]  >  0 :  min_height  =  min ( min_height ,  height [ v ])  height [ u ]  =  min_height  +  1 def  discharge ( u ):  while  extra [ u ]  >  0 :  if  seen [ u ]  <  n :  # проверить следующего соседа  v  =  seen [ u ]  if  C [ u ][ v ]  -  F [ u ][ v ]  >  0  and  height [ u ]  >  height [ v ]:  push ( u ,  v )  else :  seen [ u ]  +=  1  else :  # мы проверили всех соседей. необходимо перемаркировать  relabel ( u )  seen [ u ]  =  0 height [ source ]  =  n  # самый длинный путь от источника до стока меньше n long  extra [ source ]  =   # отправить как можно больше потока соседям источника  for  v  in  range ( n ):  push ( source ,  v ) p  =  0  while  p  <  len ( nodelist ):  u  =  nodelist [ p ]  old_height  =  height [ u ]  discharge ( u )  if  height [ u ]  >  old_height :  nodelist . insert ( 0 ,  nodelist . pop ( p ))  # перейти в начало списка  p  =  0  # начать с начала списка  else :  p  +=  1 возврат  суммы ( F [ источник ])

Ссылки

  1. ^ abc Cormen, TH ; Leiserson, CE ; Rivest, RL ; Stein, C. (2001). "§26 Максимальный поток". Введение в алгоритмы (2-е изд.). The MIT Press. стр. 643–698. ISBN 978-0262032933.
  2. ^ abcdefg Голдберг, А. В.; Тарьян, Р. Э. (1986). "Новый подход к проблеме максимального потока". Труды восемнадцатого ежегодного симпозиума ACM по теории вычислений – STOC '86 . стр. 136. doi :10.1145/12130.12144. ISBN 978-0897911931. S2CID  14492800.
  3. ^ ab Ахуджа, Равиндра К.; Кодиалам, Мурали; Мишра, Аджай К.; Орлин, Джеймс Б. (1997). "Вычислительные исследования алгоритмов максимального потока". Европейский журнал операционных исследований . 97 (3): 509. CiteSeerX 10.1.1.297.2945 . doi :10.1016/S0377-2217(96)00269-X. 
  4. ^ abc Goldberg, Andrew V. (2008). "The Partial Augment–Relabel Algorithm for the Maximum Flow Problem". Алгоритмы – ESA 2008. Lecture Notes in Computer Science. Vol. 5193. pp.  466– 477. CiteSeerX 10.1.1.150.5103 . doi :10.1007/978-3-540-87744-8_39. ISBN  978-3-540-87743-1.
  5. ^ Голдберг, Эндрю В. (1997). «Эффективная реализация алгоритма масштабирования потока минимальной стоимости». Журнал алгоритмов . 22 : 1–29 . doi :10.1006/jagm.1995.0805.
  6. ^ Ахуджа, Равиндра К.; Орлин, Джеймс Б. (1991). «Алгоритмы увеличивающегося пути, направленного на расстояние, для задач максимального потока и параметрического максимального потока». Naval Research Logistics . 38 (3): 413. CiteSeerX 10.1.1.297.5698 . doi :10.1002/1520-6750(199106)38:3<413::AID-NAV3220380310>3.0.CO;2-J. 
  7. ^ Голдберг, Эндрю В.; Тарьян, Роберт Э. (2014). «Эффективные алгоритмы максимального потока». Сообщения ACM . 57 (8): 82. doi :10.1145/2628036. S2CID  17014879.
  8. ^ abcde Голдберг, Эндрю В.; Тарьян, Роберт Э. (1988). "Новый подход к проблеме максимального потока". Журнал ACM . 35 (4): 921. doi : 10.1145/48014.61051 . S2CID  52152408.
  9. ^ ab Ахуджа, РК; Магнанти, TL; Орлин, Дж. Б. (1993). Сетевые потоки: теория, алгоритмы и приложения (1-е изд.). Prentice Hall. ISBN 978-0136175490.
  10. ^ Шилоах, Йосси; Вишкин, Узи (1982). «Параллельный алгоритм максимального потока O(n2log n)». Журнал алгоритмов . 3 (2): 128– 146. doi :10.1016/0196-6774(82)90013-X.
  11. ^ Cheriyan, J.; Maheshwari, SN (1988). "Анализ алгоритмов проталкивания предпотока для максимального сетевого потока". Основы технологии программного обеспечения и теоретической информатики . Конспект лекций по информатике. Том 338. стр. 30. doi :10.1007/3-540-50517-2_69. ISBN 978-3-540-50517-4.
  12. ^ Черкасский, Борис В.; Голдберг, Эндрю В. (1995). "О реализации метода push-relabel для задачи максимального потока". Целочисленное программирование и комбинаторная оптимизация . Конспект лекций по информатике. Том 920. стр. 157. CiteSeerX 10.1.1.150.3609 . doi :10.1007/3-540-59408-6_49. ISBN  978-3-540-59408-6.
  13. ^ Деригс, У.; Мейер, В. (1989). «Реализация алгоритма максимального потока Голдберга? Вычислительное исследование». Zeitschrift für Operations Research . 33 (6): 383. дои : 10.1007/BF01415937. S2CID  39730584.
Получено с "https://en.wikipedia.org/w/index.php?title=Push–relabel_maximum_flow_algorithm&oldid=1262038893"