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