Редактирование: Алгоритм Голдберга-Тарьяна
Внимание! Вы не авторизовались на сайте. Ваш IP-адрес будет публично видимым, если вы будете вносить любые правки. Если вы войдёте или создадите учётную запись, правки вместо этого будут связаны с вашим именем пользователя, а также у вас появятся другие преимущества.
Правка может быть отменена. Пожалуйста, просмотрите сравнение версий, чтобы убедиться, что это именно те изменения, которые вас интересуют, и нажмите «Записать страницу», чтобы изменения вступили в силу.
Текущая версия | Ваш текст | ||
Строка 1: | Строка 1: | ||
− | '''Алгоритм Голдберга-Тарьяна''' (англ | + | '''Алгоритм Голдберга-Тарьяна''' (англ ''Goldberg-Tarjan'') - алгоритм, решающий задачу нахождения максимального потока в транспортной сети за <tex>O(VE \log(VE))</tex>. Можно считать модификацией Алгоритма Диница. |
− | + | ==Идея== | |
− | + | Вспомним [[Схема алгоритма Диница|Алгоритм Диница]]. Пусть есть сеть <tex>G^0_f </tex> {{---}} некоторый ориентированный ациклический граф, <tex>S</tex>, <tex>T</tex> {{---}} исток и сток соответственно. Схема Алгоритма Диница : | |
− | Вспомним [[Схема алгоритма Диница| | ||
# При помощи [[Обход в глубину, цвета вершин|обхода в глубину]] находим путь из <tex>S</tex> в <tex>T</tex>. | # При помощи [[Обход в глубину, цвета вершин|обхода в глубину]] находим путь из <tex>S</tex> в <tex>T</tex>. | ||
# Находим ребро с минимальной пропускной способностью | # Находим ребро с минимальной пропускной способностью | ||
Строка 14: | Строка 13: | ||
Пусть каждое дерево поддерживает следующие операции: | Пусть каждое дерево поддерживает следующие операции: | ||
− | # Вычислить минимум на пути от вершины до корня | + | # Вычислить минимум на пути от вершины до корня |
− | # Прибавить константу к числам на пути от вершины до корня | + | # Прибавить константу к числам на пути от вершины до корня. |
− | # Отрезать поддерево по ребру. Отрезанное поддерево отделяется и существует независимо от исходного дерева | + | # Отрезать поддерево по ребру. Отрезанное поддерево отделяется и существует независимо от исходного дерева. |
− | # Подвесить дерево. Пусть есть дерево с корнем <tex>A</tex>, дерево с вершиной <tex>B</tex>. Операция позволяет Создать ребро из <tex>A</tex> в <tex>B</tex> и тем самым подвесить дерево к вершине | + | # Подвесить дерево. Пусть есть дерево с корнем <tex>A</tex>, дерево с вершиной <tex>B</tex>. Операция позволяет Создать ребро из <tex>A</tex> в <tex>B</tex> и тем самым подвесить дерево к вершине. |
− | Заметим, что именно эти операции поддерживает [[Link-Cut Tree| | + | Заметим, что именно эти операции поддерживает [[Link-Cut Tree|Linking-Cutting Tree]] и умеет их выполнять за <tex>O(\log(N))</tex> |
− | + | ==Поиск пути== | |
Научимся находить путь из <tex>S</tex> в <tex>T</tex> в описанной выше сети при помощи леса корневых деревьев. Будем отдельно хранить дерево с потоками и дерево с пропускными способностями. | Научимся находить путь из <tex>S</tex> в <tex>T</tex> в описанной выше сети при помощи леса корневых деревьев. Будем отдельно хранить дерево с потоками и дерево с пропускными способностями. | ||
− | + | Пусть <tex>U</tex> {{---}} корень дерева, в котором лежит <tex>S</tex>. | |
− | + | ||
− | * | + | * Заметим, что если <tex>S</tex>, <tex>T</tex> лежат в одном дереве, то путь ищется легко. Это путь по дереву до корня. |
− | * | + | |
− | + | * Если <tex>S</tex>, <tex>T</tex> лежат в разных деревьях. Просмотрим все ненасыщенные исходящие ребра. Будем рассматривать их также, как и в Алгоритме Диница, с глобальным итератором. Т.е начинать просмотр будем с последнего подошедшего ребра. Если ребро не подошло - больше его не рассматриваем. Пусть просматриваем какое-то ненасыщенное ребро, ведущее в некоторую вершину <tex>V</tex>: | |
− | + | # Подвесим корень <tex>U</tex> через это ребро к вершине V (Операция 3). | |
− | + | #В <tex>U</tex> записываем число, равное остаточной пропускной способности ребра. | |
− | * | + | |
− | + | * Будем повторять, пока <tex>S</tex> и <tex>T</tex> не окажутся в одном дереве. | |
− | + | ==Улучшение пути== | |
Путь из <tex>S</tex> в <tex>T</tex> найден, теперь научимся улучшать путь. Нужно обновить значения пропускных способностей и потоков через вершины этого пути. Тогда: | Путь из <tex>S</tex> в <tex>T</tex> найден, теперь научимся улучшать путь. Нужно обновить значения пропускных способностей и потоков через вершины этого пути. Тогда: | ||
− | + | # При помощи <tex>(1)</tex> запроса можно найти узкое место (ребро с минимальной остаточной пропускной способностью) на этом пути и его пропускную способность. | |
− | + | # При помощи <tex>(2)</tex> запроса можно вычесть из всех ребер на этом пути пропускную способность узкого места, а также, прибавить ее к потоку. | |
− | Пусть после <tex>(2)</tex> запроса появилось нулевое ребро. Запрос минимума от <tex>S</tex> до корня будет возвращать | + | Пусть после <tex>(2)</tex> запроса появилось нулевое ребро. Запрос минимума от <tex>S</tex> до корня будет возвращать 0. Поэтому, такие ребра нужно отрезать, выполнив <tex>(3)</tex> запрос по этому ребру. |
− | == | + | ==Алгоритм== |
− | Объединим вышесказанное в | + | Объединим вышесказанное в Алгоритм Голдберга-Татьяна. |
Пусть дана сеть. Требуется в этой сети найти поток <tex>f(S, T) </tex> максимальной величины. | Пусть дана сеть. Требуется в этой сети найти поток <tex>f(S, T) </tex> максимальной величины. | ||
− | + | # Для каждого ребра <tex>(u, v)</tex> данной сети <tex>G</tex> зададим <tex>f(u, v) = 0</tex> | |
− | + | # Пока есть путь из <tex>S</tex> в <tex>T</tex>: | |
− | + | ## Выполняем запрос <tex>(1)</tex>, находим узкое место и пропускную способность | |
− | + | ## Обновляем значения потока и пропускной способности при помощи запроса <tex>(2)</tex> | |
− | + | ## Обрезаем нулевые ребра при помощи запроса <tex>(4)</tex> | |
− | |||
− | |||
==Время работы== | ==Время работы== | ||
− | [[Link-Cut Tree| | + | [[Link-Cut Tree|Linking-Cutting Tree]] выполняет все вышеописанные запросы за <tex>O(\log(N))</tex>, оценим время работы алгоритма. |
Очевидно, что просмотров ребер суммарно <tex>O(E)</tex>, как и в алгоритме Диница. Переход к следующему ребру происходит в следующих случаях: | Очевидно, что просмотров ребер суммарно <tex>O(E)</tex>, как и в алгоритме Диница. Переход к следующему ребру происходит в следующих случаях: | ||
− | # | + | # просматриваемое ребро насыщено |
− | # | + | # дерево разрезается по нулевому ребру |
− | # | + | # ребро не лежит в сети кратчайших путей |
На каждый просмотр тратится не <tex>O(1)</tex> а <tex>O(\log(V))</tex>, потому что перед тем, как посмотреть на следующее ребро делается запрос. Значит время работы этой части {{---}} <tex>O(E \log(V))</tex>. | На каждый просмотр тратится не <tex>O(1)</tex> а <tex>O(\log(V))</tex>, потому что перед тем, как посмотреть на следующее ребро делается запрос. Значит время работы этой части {{---}} <tex>O(E \log(V))</tex>. | ||
− | Следующий шаг в алгоритме Диница | + | Следующий шаг в алгоритме Диница - сумма длин путей. Раньше считалось за <tex>O(V^2)</tex>. Потому, что на каждый путь DFS тратил время, пропорциональное длине этого пути. Сейчас тратится только <tex>O(\log(V))</tex> на каждый путь. Если путь найден, значит до него дошли, значит это соответствует одному запросу. Поэтому тратим на каждый путь тоже логарифм <tex>O(\log(V))</tex>. |
− | |||
− | |||
− | = | + | Тогда имеем ассимптотику <tex>O(E\log(V) + V \log(V)) = O((V + E) \log(V))</tex>. И, суммарно, если подставить в Алгоритм Диница будем иметь ассимптотику <tex>O(VE \log(V)) </tex> |
− | |||
− | |||
− | |||
− | |||
− | == Источники | + | == Источники == |
*[https://www.lektorium.tv/lecture/14408 Lektorium {{---}} Лекция А.С. Станкевича] | *[https://www.lektorium.tv/lecture/14408 Lektorium {{---}} Лекция А.С. Станкевича] | ||
[[Категория: Алгоритмы и структуры данных]] | [[Категория: Алгоритмы и структуры данных]] | ||
[[Категория: Задача о максимальном потоке ]] | [[Категория: Задача о максимальном потоке ]] |