Алгоритм отмены цикла минимального среднего веса — различия между версиями
(→Псевдокод) |
м (rollbackEdits.php mass rollback) |
||
(не показаны 23 промежуточные версии 3 участников) | |||
Строка 21: | Строка 21: | ||
===Псевдокод=== | ===Псевдокод=== | ||
− | ''' | + | '''Edge[]''' findMin('''Graph''' G) |
− | + | '''while''' f | |
− | + | <font color="green">// найдём M(C) {{---}} вес минимального цикла</font> | |
− | + | C = c : M(c) = <tex>\min\limits_c</tex> M(c) | |
− | + | '''if''' M(C) <tex>\geqslant</tex> 0 | |
− | + | <font color="green">// Если величина M(C) положительна, то мы нашли f {{---}} поток минимальной стоимости, на этом алгоритм завершается</font> | |
− | + | '''return''' f | |
+ | '''else''' | ||
+ | <font color="green">// в противном случае отменяем цикл</font> | ||
+ | f += c_f * f(C) | ||
===Корректность=== | ===Корректность=== | ||
Строка 132: | Строка 135: | ||
====Псевдокод==== | ====Псевдокод==== | ||
− | + | '''func''' findMinCycleBinarySearch('''int''' l, '''int''' r) | |
− | m = (l + r) / < | + | <font color="green">// находим среднюю величину <tex>m</tex></font> |
+ | m = (l + r) / 2 | ||
+ | <font color="green">// вычитаем её из веса каждого ребра в сети</font> | ||
'''for''' e '''in''' edges | '''for''' e '''in''' edges | ||
− | + | e.weight -= m | |
− | '''if''' M(C) < 0 <!--- cho-t xz za4em C: mb exists? ---> | + | '''while''' l > r - 1 |
− | + | <!-----<font color="green">// добавляем мнимую вершину <tex>s</tex> и проводим рёбра нулевого веса в каждую вершину графа</font>---------> | |
− | + | '''if''' <tex>\exists</tex>C : M(C) < 0 <!--- cho-t xz za4em C: mb exists? eee ugadala)0))---> | |
− | + | <font color="green">// если есть отрицательный цикл, то веса циклов находятся в диапазоне <tex>[l;m]</tex> | |
+ | // рассмотрим этот промежуток</font> | ||
+ | findMinCycleBinarySearch (l, m) | ||
+ | '''else''' | ||
+ | <font color="green">// иначе запускаем двоичный поиск на отрезке <tex>[m;r]</tex></font> | ||
+ | findMinCycleBinarySearch (m, r) | ||
===Продвинутый алгоритм=== | ===Продвинутый алгоритм=== | ||
− | Добавим к нашему графу вершину <tex>s</tex> и | + | Добавим к нашему графу вершину <tex>s</tex> и рёбра из неё во все остальные вершины. |
Запустим [[алгоритм Форда-Беллмана]] и попросим его построить нам квадратную матрицу со следующим условием: <tex>d[i][u]</tex> {{---}} длина минимального пути от <tex>s</tex> до <tex>u</tex> ровно из <tex>i</tex> ребер. | Запустим [[алгоритм Форда-Беллмана]] и попросим его построить нам квадратную матрицу со следующим условием: <tex>d[i][u]</tex> {{---}} длина минимального пути от <tex>s</tex> до <tex>u</tex> ровно из <tex>i</tex> ребер. | ||
Тогда длина оптимального цикла <tex>\mu^{*}</tex> минимального среднего веса вычисляется как <tex>\min\limits_{u} {\max\limits_{k} {\dfrac{d[n][u]-d[k][u]}{n-k}}}</tex>. | Тогда длина оптимального цикла <tex>\mu^{*}</tex> минимального среднего веса вычисляется как <tex>\min\limits_{u} {\max\limits_{k} {\dfrac{d[n][u]-d[k][u]}{n-k}}}</tex>. | ||
Строка 153: | Строка 163: | ||
====Псевдокод==== | ====Псевдокод==== | ||
− | '''func''' findMinCycle( | + | '''func''' findMinCycle('''Graph''' G) |
− | + | <font color="green">// вводим мнимую вершину <tex>s</tex>, от которой проведём рёбра нулевого веса в каждую вершину графа</font> | |
− | + | '''Node''' s | |
− | + | '''Edge[]''' e | |
− | + | insert(s) | |
− | + | i = 0 | |
− | + | '''for''' u '''in''' G | |
− | + | e[i].begin = s | |
− | + | e[i].end = u | |
− | + | e[i].weight = 0 | |
+ | i++ | ||
+ | <font color="green">// строим матрицу кратчайших расстояний, запустив алгоритм Форда-Беллмана из вершины <tex>s</tex></font> | ||
+ | fordBellman(s) | ||
+ | <font color="green">// <tex>m</tex> {{---}} длина оптимального цикла</font> | ||
+ | m = <tex>\min\limits_{u} {\max\limits_{k} }</tex>((d[n][u] - d[k][u]) / (n - k)) | ||
+ | <!-----<font color="green">// запомнив значения <tex>u</tex> и <tex>k</tex>, дающих оптимальный результат, найдём цикл</font>---------> | ||
+ | <!----чуть не забыла про отступы, дура тупая-----> | ||
==См. также== | ==См. также== |
Текущая версия на 19:26, 4 сентября 2022
В статье описывается один из сильно полиномиальных алгоритмов решения задачи о поиске потока минимальной стоимости.
Содержание
[убрать]Алгоритм
Приведенный алгоритм основан на идее алгоритма Клейна отмены цикла отрицательного веса. Выбор цикла минимального среднего веса вместо случайного делает алгоритм сильно полиномиальным.
Определение: |
Сильно полиномиальными (англ. strongly polynomial) в контексте данной задачи называются алгоритмы, чья сложность полиномиально зависит от | и .
Описание
Обозначим как пропускную способность цикла при протекании в сети потока . Cтоимость цикла обозначим за , а длину (число входящих в него ребер) — за .
остаточнуюОпределение: |
Средним весом (англ. mean weight) цикла будем называть отношение его стоимости к его длине |
Данный алгоритм заключается в последовательной отмене циклов минимального среднего веса в остаточной сети посредством их насыщения. Алгоритм работает до тех пор, пока минимальный средний вес циклов не окажется положительным, что будет означать, что поток минимальной стоимости найден.
Более формально:
- Шаг . Рассмотрим некоторый поток .
- Шаг . Найдем цикл , обладающий наименьшим средним весом. Если , то — поток минимальной стоимости и алгоритм завершается.
- Шаг . Отменим цикл , пустив по нему максимально возможный поток: . Перейдем к шагу .
Сложность
Для сетей с целочисленными стоимостями на ребрах
, с вещественными — . В обоих случаях времени тратится на поиск цикла минимального среднего веса.Псевдокод
Edge[] findMin(Graph G) while f // найдём M(C) — вес минимального цикла C = c : M(c) =M(c) if M(C) 0 // Если величина M(C) положительна, то мы нашли f — поток минимальной стоимости, на этом алгоритм завершается return f else // в противном случае отменяем цикл f += c_f * f(C)
Корректность
Пусть потенциалов .
— поток минимальной стоимости. Введём на нашей сети функциюОпределение: |
Приведённой стоимостью (англ. reduced cost) ребра назовем следующую величину: | .
Иными словами, приведённая стоимость — это сколько нужно потратить денег, чтобы перевезти единицу жидкости из
в (её нужно купить в , перевезти из в и продать в ).Лемма ( | ):
Если — поток минимальной стоимости, то такое, что . |
Доказательство: |
|
Определение: |
Будем говорить, что поток | — -оптимальный (англ. -optimal), если такая, что .
Лемма ( | ):
Если стоимости целочисленны и поток — -оптимальный, где , то — поток минимальной стоимости. |
Доказательство: |
|
Обозначим за
минимальную величину среди средних весов циклов для потока , а за минимальное такое, что поток — -оптимальный.Лемма ( | ):
Если — поток не минимальной стоимости, то . |
Доказательство: |
|
Лемма ( | ):
Отмена цикла минимального среднего веса не увеличивает . |
Доказательство: |
|
Определение: |
Допустимым графом (англ. admissible graph) будем называть такой подграф остаточной сети, что он включает только ребра отрицательной приведенной стоимости. |
Лемма ( | ):
Пусть — некоторый поток, а — поток после отмен циклов минимального среднего веса. Тогда , где — минимальное такое, что поток -оптимальный. |
Доказательство: |
|
Определение: |
-фиксированным (англ. -fixed) будем называть ребро, поток через которое неизменен для любых -оптимальных потоков в сети. |
Теорема: |
Пусть поток является -оптимальным с функцией потенциалов . Также пусть для некоторого ребра . Тогда ребро -фиксировано. |
Доказательство: |
|
Лемма (доказательство оценки времени работы алгоритма в случае вещественных стоимостей): |
Пусть . Разобьем работу алгоритма на группы по последовательных итераций. Утверждается, что каждая группа фиксирует поток на независимом ребре , то есть итерации из другой группы не меняют величину . |
Доказательство: |
|
Алгоритм поиска цикла минимального среднего веса
Наивный способ
Устроим двоичный поиск. Установим нижнюю и верхнюю границы величины среднего веса цикла и соответственно, вычислим серединное значение и отнимем полученную величину от всех ребер сети. Если теперь в нашей сети есть отрицательный цикл (этот факт можно проверить при помощи алгоритма Форда-Беллмана), значит существует цикл с меньшим средним весом, чем . Тогда продолжим поиск среди значений в диапазоне от до , иначе — от до .
Тогда, если
и — максимальная и минимальная возможные величины среднего веса цикла соответственно, такой алгоритм для вещественных значений весов ребер будет работать за , где — точность выбора среднего веса цикла. При этом для целочисленных значений на ребрах точность выбора величины среднего веса цикла не может превысить , что дает нам оценку .Псевдокод
func findMinCycleBinarySearch(int l, int r) // находим среднюю величинуm = (l + r) / 2 // вычитаем её из веса каждого ребра в сети for e in edges e.weight -= m while l > r - 1 if C : M(C) < 0 // если есть отрицательный цикл, то веса циклов находятся в диапазоне // рассмотрим этот промежуток findMinCycleBinarySearch (l, m) else // иначе запускаем двоичный поиск на отрезке findMinCycleBinarySearch (m, r)
Продвинутый алгоритм
Добавим к нашему графу вершину алгоритм Форда-Беллмана и попросим его построить нам квадратную матрицу со следующим условием: — длина минимального пути от до ровно из ребер. Тогда длина оптимального цикла минимального среднего веса вычисляется как .
и рёбра из неё во все остальные вершины. ЗапустимДостаточно будет доказать это правило для
, так как для других можно просто отнять эту величину от всех ребер и получить снова случай с .Чтобы найти цикл после построения матрицы
, запомним, при каких и достигается оптимальное значение , и, используя , поднимемся по указателям предков. Как только мы попадем в уже посещенную вершину — мы нашли цикл минимального среднего веса.Этот алгоритм работает за [2].
Псевдокод
func findMinCycle(Graph G) // вводим мнимую вершину, от которой проведём рёбра нулевого веса в каждую вершину графа Node s Edge[] e insert(s) i = 0 for u in G e[i].begin = s e[i].end = u e[i].weight = 0 i++ // строим матрицу кратчайших расстояний, запустив алгоритм Форда-Беллмана из вершины fordBellman(s) // — длина оптимального цикла m = ((d[n][u] - d[k][u]) / (n - k))
См. также
- Использование потенциалов Джонсона при поиске потока минимальной стоимости
- Сведение задачи о назначениях к задаче о потоке минимальной стоимости
Примечания
Источники информации
- Лекция 14 | Дополнительные главы алгоритмов | Андрей Станкевич | CSC | Лекториум
- A.V.Goldberg and R.E.Tarjan — Finding Minimum-Cost Circulations by Cancelling Negative Cycles (Journal of the Association for Computing Machinery. Vol. 36, No. 4. October 1989. pp. 873-886.)
- Lecture by M.X.Goemans on Goldberg-Tarjan Min-Cost Circulation Algorithm