Алгоритм вырезания соцветий — различия между версиями
Kot (обсуждение | вклад) (→Алгоритм вырезания соцветий) |
Kot (обсуждение | вклад) (→Алгоритм вырезания соцветий) |
||
Строка 36: | Строка 36: | ||
Пусть дан произвольный граф <tex>G(V, E)</tex> и требуется найти максимальное паросочетание в нём. <br> | Пусть дан произвольный граф <tex>G(V, E)</tex> и требуется найти максимальное паросочетание в нём. <br> | ||
+ | |||
+ | ===Общая идея=== | ||
+ | |||
+ | #Сжимаем все соцветия | ||
+ | #Находим паросочетания в полученном графе поиском в глубину/ширину. | ||
+ | #Разжимаем соцветия, восстанавливая паросочетание. | ||
+ | |||
+ | ===Пошаговое представление=== | ||
+ | |||
Алгоритм строит лес, содержащий деревья удлиняющих путей, корнями которых являются вершины не из паросочетания. | Алгоритм строит лес, содержащий деревья удлиняющих путей, корнями которых являются вершины не из паросочетания. | ||
Строка 44: | Строка 53: | ||
Также для каждой вершины <tex>v</tex> алгоритм в <tex>p(v)</tex> будет хранить родителя в дереве обхода. | Также для каждой вершины <tex>v</tex> алгоритм в <tex>p(v)</tex> будет хранить родителя в дереве обхода. | ||
− | Сначала | + | Сначала пометим все вершины, включенные в паросочетание, непосещенными, все остальные - четными. |
+ | |||
+ | Пока существует удлиняющий путь или пока есть непроверенное ребро из четной вершины <tex>v</tex>: | ||
+ | #Выберем любое непроверенное ребро<tex>(v, w)</tex> из четной вершины <tex>v</tex> и проверяем: | ||
+ | #*Вершина <tex>w</tex> нечетное - ничего не делаем. Такая ситуация возникает, когда <tex>(v, w)</tex> ребро из паросочетания или не из паросочетания | ||
+ | #*Вершина <tex>w</tex> включено в паросочетание и непосещенное. Тогда помечаем <tex>w</tex> нечетным, а <tex>mate(w)</tex> четным. Присваиваем <tex>p(w) \gets v</tex>, а также <tex>p(mate(w)) \gets w</tex> | ||
+ | #*<tex>w</tex> четное; вершины <tex>w, v</tex> лежат в разных деревьях - нашли удлиняющий путь от корня дерева, содержащего вершину <tex>v</tex> до корня дерева, содержащего вершину <tex>w</tex>. | ||
+ | #*<tex>w</tex> четное; вершины <tex>w, v</tex> лежат в одном дереве - нашли соцветие. Пусть <tex>u</tex> - наименьший общий предок вершин <tex>v</tex> и <tex>w</tex>. Сожмем соцветие в псевдо-вершину <tex>b</tex>, <tex>p(b) \gets p(u)</tex>, а также для каждой вершины <tex>x</tex> в соцветии определим <tex>p(x) \gets b</tex> | ||
+ | |||
+ | ===Псевдокод=== | ||
+ | '''Edmonds''' { | ||
+ | '''for''' <tex>u \in V</tex>''' | ||
+ | if (вершина u не в паросочетании)''' { | ||
+ | '''int''' '''last_v''' = '''find_augment_path''' (u); | ||
+ | '''if (last_v != -1)''' | ||
+ | '''выполнить чередование вдоль пути из u в last_v;''' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | int find_augment_path (root) { | ||
+ | обход в ширину: | ||
+ | v = текущая_вершина; | ||
+ | for <tex>(v,w) \in E</tex> | ||
+ | если обнаружили цикл нечётной длины, сжать его | ||
+ | если пришли в свободную вершину, return | ||
+ | если пришли в несвободную вершину, то добавить в очередь смежную ей в паросочетании | ||
+ | return -1; | ||
+ | } |
Версия 23:12, 15 января 2011
Содержание
Паросочетание в недвудольном графе
Определение: |
Соцветие | графа - цикл, состоящий из ребер, из которых только входят в соцветие .
Определение: |
Cжатие соцветия - граф | , полученный из сжатием соцветия в одну псевдо-вершину.
Определение: |
База соцветия - вершина соцветия, в которую входит ребро не из данного соцветия. |
Теорема Эдмондса
Теорема: |
Пусть в графе существует соцветие .Тогда в существует удлиняющий путь тогда и только тогда, когда существует удлиняющий путь в |
Доказательство: |
Пусть граф
Пусть путь
Пусть путь Рассмотрим отдельно случай, когда Пусть теперь путь начинается со сжатого соцветия , т.е. имеет вид . Тогда в соцветии найдётся соответствующая вершина , которая связана ребром с . Заметим, что из базы соцветия всегда найдётся чередующийся путь чётной длины до вершины . Учитывая всё вышесказанное, получаем, что путь является увеличивающим путём в графе . проходит через псевдо-вершину , но не начинается и не заканчивается в ней. Тогда в есть два ребра, проходящих через , пусть это и . Одно из них обязательно должно принадлежать паросочетанию, однако, так как база цветка не насыщена, а все остальные вершины цикла цветка насыщены рёбрами цикла, то мы приходим к противоречию (это эквивалентно случаю отсутствия ребра из ). Таким образом, этот случай просто невозможен. Теорема доказана. в |
Алгоритм вырезания соцветий
Пусть дан произвольный граф
Общая идея
- Сжимаем все соцветия
- Находим паросочетания в полученном графе поиском в глубину/ширину.
- Разжимаем соцветия, восстанавливая паросочетание.
Пошаговое представление
Алгоритм строит лес, содержащий деревья удлиняющих путей, корнями которых являются вершины не из паросочетания.
Разобьем каждое неориентированное ребро
на два ориентированных ребра и . Каждое ребро может принимать одно из трех состояний: непосещенное, четное и нечетное. Для каждой вершины из паросочетания в будем хранить вершину, смежную . Также для каждой вершины алгоритм в будет хранить родителя в дереве обхода.Сначала пометим все вершины, включенные в паросочетание, непосещенными, все остальные - четными.
Пока существует удлиняющий путь или пока есть непроверенное ребро из четной вершины
:- Выберем любое непроверенное ребро
- Вершина нечетное - ничего не делаем. Такая ситуация возникает, когда ребро из паросочетания или не из паросочетания
- Вершина включено в паросочетание и непосещенное. Тогда помечаем нечетным, а четным. Присваиваем , а также
- четное; вершины лежат в разных деревьях - нашли удлиняющий путь от корня дерева, содержащего вершину до корня дерева, содержащего вершину .
- четное; вершины лежат в одном дереве - нашли соцветие. Пусть - наименьший общий предок вершин и . Сожмем соцветие в псевдо-вершину , , а также для каждой вершины в соцветии определим
из четной вершины и проверяем:
Псевдокод
Edmonds { forif (вершина u не в паросочетании) { int last_v = find_augment_path (u); if (last_v != -1) выполнить чередование вдоль пути из u в last_v; } } int find_augment_path (root) { обход в ширину: v = текущая_вершина; for если обнаружили цикл нечётной длины, сжать его если пришли в свободную вершину, return если пришли в несвободную вершину, то добавить в очередь смежную ей в паросочетании return -1; }