Алгоритм Куна для поиска максимального паросочетания — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Теорема)
Строка 4: Строка 4:
 
  Если из вершины <tex>x</tex> не существует дополняющей цепи относительно паросочетания <tex>M</tex> и паросочетание <tex>M'</tex> получается из <tex>M</tex> изменением вдоль дополняющей цепи, тогда из <tex>x</tex> не существует дополняющей цепи в <tex>M'</tex>.
 
  Если из вершины <tex>x</tex> не существует дополняющей цепи относительно паросочетания <tex>M</tex> и паросочетание <tex>M'</tex> получается из <tex>M</tex> изменением вдоль дополняющей цепи, тогда из <tex>x</tex> не существует дополняющей цепи в <tex>M'</tex>.
 
|proof=
 
|proof=
[[Файл:Kuhn1.png|thumb|left|300x300px|Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]
+
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]
[[Файл:Kuhn2.png|thumb|right|300x300px|]]
+
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.<br>Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]
Доказательство от противного. Допустим в паросочетание внесли изменения вдоль дополняющей цепи <tex>(y \rightsquigarrow z)</tex> и из вершины <tex>x</tex> появилась дополняющая цепь. Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из <tex>x</tex> существовала и в исходном паросочетании. Пусть <tex>p</tex> - ближайшая к <tex>x</tex> вершина, которая принадлежит и новой дополняющей цепи и цепи <tex>(y \rightsquigarrow z)</tex>. Тогда <tex>MP</tex> - последнее ребро на отрезке <tex>(y \rightsquigarrow p)</tex> цепи <tex>(y \rightsquigarrow z)</tex>, <tex>NP</tex> - последнее ребро на отрезке <tex>(z \rightsquigarrow p)</tex> цепи <tex>(y \rightsquigarrow z)</tex>, <tex>QP</tex> - последнее ребро лежащее на отрезке <tex>(x \rightsquigarrow p)</tex> новой дополняющей цепи.(см. рисунок). Допустим <tex>MP</tex> принадлежит паросочетанию <tex>M'</tex>, тогда <tex>NP</tex> ему не принадлежит. Поскольку паросочетание <tex>M'</tex> получается из <tex>M</tex> изменением вдоль дополняющей цепи <tex>(y \rightsquigarrow z)</tex>, в паросочетание <tex>M</tex> входило ребро <tex>NP</tex>, а ребро <tex>MP</tex> нет. Кроме того, ребро <tex>QP</tex> не лежит ни в исходном паросочетании <tex>M</tex>, ни в паросочетании <tex>M'</tex>, в противном случае оказалось бы, что вершина <tex>p</tex> инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания. Тогда заметим, что цепь <tex>(x \rightsquigarrow z)</tex>, полученная объединением цепей <tex>(x \rightsquigarrow p)</tex> и <tex>(p \rightsquigarrow z)</tex>, по определению будет дополняющей в паросочетании <tex>M</tex>, что приводит к противоречию, поскольку в паросочетании <tex>M</tex> из вершины <tex>x</tex> не существует дополняющей цепи.
+
: Доказательство от противного.<br><br>
 +
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи <tex>(y \rightsquigarrow z)</tex> и из вершины <tex>x</tex> появилась дополняющая цепь.
 +
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из <tex>x</tex> существовала и в исходном паросочетании.<br><br>
 +
: Пусть <tex>p</tex> - ближайшая к <tex>x</tex> вершина, которая принадлежит и новой дополняющей цепи и цепи <tex>(y \rightsquigarrow z)</tex>.
 +
: Тогда <tex>MP</tex> - последнее ребро на отрезке <tex>(y \rightsquigarrow p)</tex> цепи <tex>(y \rightsquigarrow z)</tex>, <tex>NP</tex> - последнее ребро на отрезке <tex>(z \rightsquigarrow p)</tex> цепи <tex>(y \rightsquigarrow z)</tex>, <tex>QP</tex> - последнее ребро лежащее на отрезке <tex>(x \rightsquigarrow p)</tex> новой дополняющей цепи(см. Рисунок 1).<br><br>
 +
: Допустим <tex>MP</tex> принадлежит паросочетанию <tex>M'</tex>, тогда <tex>NP</tex> ему не принадлежит.<br><br>
 +
: Поскольку паросочетание <tex>M'</tex> получается из <tex>M</tex> изменением вдоль дополняющей цепи <tex>(y \rightsquigarrow z)</tex>, в паросочетание <tex>M</tex> входило ребро <tex>NP</tex>, а ребро <tex>MP</tex> нет.
 +
: Кроме того, ребро <tex>QP</tex> не лежит ни в исходном паросочетании <tex>M</tex>, ни в паросочетании <tex>M'</tex>, в противном случае оказалось бы, что вершина <tex>p</tex> инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.<br><br>
 +
:Тогда заметим, что цепь <tex>(x \rightsquigarrow z)</tex>, полученная объединением цепей <tex>(x \rightsquigarrow p)</tex> и <tex>(p \rightsquigarrow z)</tex>, по определению будет дополняющей в паросочетании <tex>M</tex>, что приводит к противоречию, поскольку в паросочетании <tex>M</tex> из вершины <tex>x</tex> не существует дополняющей цепи.
 
}}
 
}}
  
 
==Алгоритм==
 
==Алгоритм==
Пусть дан двудольный граф <tex>G(V, E)</tex> и требуется найти максимальное паросочетание в нём. Обозначим доли исходного графа как <tex>L</tex> и <tex>R</tex>. <br>
 
1) Просматриваем вершины <tex>s</tex> из доли <tex>L</tex>.
 
  
2) Будем искать дополняющую цепь из <tex>s</tex> (например, поиском в глубину).  
+
:Алгоритм Куна — непосредственное применение [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы Бержа]].<br><br>
 +
:Алгоритм просматривает все вершины графа по очереди, запуская из каждой обход (в глубину или в ширину), пытающийся найти увеличивающую цепь, начинающуюся в этой вершине.
  
3) Если цепь найдена, инвертируем все ребра на этой цепи.
+
:Краткое описание алгоритма:
 +
:* Возьмём пустое паросочетание
 +
:* Пока в графе удаётся найти увеличивающую цепь, выполняем чередование паросочетания вдоль этой цепи
 +
:* Повторяем процесс поиска увеличивающей цепи.
 +
:* Если увеличивающую цепь найти не удалось — процесс останавливается
 +
:* Найденное паросочетание и является максимальным.
  
В любой момент времени текущим паросочетанием будет множество ребер, направленных из <tex>R</tex> в <tex>L</tex>. Корректность работы алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы Бержа]] и доказанной выше теоремы.
 
  
==Псевдокод==
+
:Будем считать, что граф уже разбит на две доли.
 +
:Просматриваем все вершины <tex>v</tex> первой доли графа <tex>v = 1 ... n_1</tex>:
 +
:*Если текущая вершина  уже насыщена текущим паросочетанием (т.е. уже выбрано какое-то смежное ей ребро), то эту вершину пропускаем
 +
:*Иначе — алгоритм пытается насытить эту вершину, для чего запускается поиск увеличивающей цепи, начинающейся с этой вершины.
  
  bool '''dfs'''(x):
+
 
    vis[x] = true
+
:Рассмотрим поиск увеличивающей цепи обходом в глубину.
    '''for''' <tex>xy \in E</tex>:
+
:* Изначально обход в глубину стоит в текущей ненасыщенной вершине <tex>v</tex> первой доли.
        k = py[y]
+
:* Просматриваем все рёбра из этой вершины, пусть текущее ребро — <tex>(v, t_0)</tex>.
        '''if''' (k == -1) or (('''not''' vis[k]) '''and''' ('''dfs'''(k))):
+
:* Если вершина ещё не насыщена паросочетанием, то, значит, мы смогли найти увеличивающую цепь: она состоит из единственного ребра <tex>(v, t_0)</tex>.
            py[y] = x
+
:** Включаем это ребро в паросочетание и прекращаем поиск увеличивающей цепи из вершины <tex>v</tex>.
            return true
+
:** Иначе, — если уже насыщена каким-то ребром <tex>(p, t_0)</tex>, то попытаемся пройти вдоль этого ребра: тем самым мы попробуем найти увеличивающую цепь, проходящую через рёбра <tex>(v, t_0), (t_0, p)</tex>. Для этого просто перейдём в нашем обходе в вершину <tex>p</tex>.
    return false
+
:*** Пробуем найти увеличивающую цепь из вершины <tex>p</tex>.
  Kuhn():
+
 
    py[] = -1
+
: Этот обход, запущенный из вершины <tex>v</tex>, либо найдёт увеличивающую цепь, и тем самым насытит вершину, либо же такой увеличивающей цепи не найдёт (и, следовательно, эта вершина  уже не сможет стать насыщенной).
    '''for''' <tex>s \in L</tex>:
+
 
        vis[] = false
+
: После того, как все вершины <tex>v = 1 ... n_1</tex> будут просмотрены, текущее паросочетание будет максимальным.
        '''dfs'''(s)
+
 
 +
==Релизация==
 +
 
 +
: Граф <tex>G</tex> хранится списками смежности <tex>g[][]</tex>
 +
: Функция <tex>dfs(v)</tex> - обход в глубину, возвращает <tex>true</tex> если есть увеличивающая цепь из вершины <tex>v</tex>.
 +
: В массиве <tex>mt</tex> хранятся паросочетания. Паросочетание есть ребро <tex>(i, mt[i])</tex>.
 +
 
 +
 
 +
bool dfs(int v)
 +
{
 +
    if (used[v])
 +
        return false;
 +
 +
    used[v] = true;
 +
    for (int i = 0; i < g[v].size(); i++)
 +
    {
 +
        int to = g[v][i];
 +
        if (mt[to] == -1 || dfs(mt[to]))
 +
        {
 +
            mt[to] = v;
 +
            return true;
 +
        }
 +
    }
 +
    return false;
 +
}
 +
 +
int main()
 +
{
 +
    ... чтение графа ...
 +
    mt.assign (k, -1);
 +
    for (int v = 0; v < n; v++)
 +
    {
 +
        used.assign(n, false);
 +
        dfs(v);
 +
    }
 +
 +
    for (int i = 0; i < k; i++)
 +
        if (mt[i] != -1)
 +
            ... вывод ...
 +
 +
}
  
 
==Время работы==
 
==Время работы==
Итак, алгоритм Куна можно представить как серию из  |<tex>L</tex>| запусков обхода в глубину на всём графе. Следовательно, всего этот алгоритм исполняется за время <tex>O(V  E)</tex>, что в худшем случае есть <tex>O(V^3)</tex>.
+
:Итак, алгоритм Куна можно представить как серию из  |<tex>L</tex>| запусков обхода в глубину на всём графе.
 +
:Следовательно, всего этот алгоритм исполняется за время <tex>O(V  E)</tex>, что в худшем случае есть <tex>O(V^3)</tex>.
  
 
==Источники==
 
==Источники==
Асанов М., Баранский В., Расин В. - Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство "Лань", 2010. — 291 стр.
+
:[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]<br>
 +
: Асанов М., Баранский В., Расин В. - Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство "Лань", 2010. — 291 стр.
 
[[Категория: Алгоритмы и структуры данных]]
 
[[Категория: Алгоритмы и структуры данных]]
 
[[Категория: Задача о паросочетании]]
 
[[Категория: Задача о паросочетании]]

Версия 09:32, 24 декабря 2011

Теорема

Теорема:
Если из вершины [math]x[/math] не существует дополняющей цепи относительно паросочетания [math]M[/math] и паросочетание [math]M'[/math] получается из [math]M[/math] изменением вдоль дополняющей цепи, тогда из [math]x[/math] не существует дополняющей цепи в [math]M'[/math].
Доказательство:
[math]\triangleright[/math]
Рисунок 1.
Рисунок 2.
Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.
Доказательство от противного.

Допустим в паросочетание внесли изменения вдоль дополняющей цепи [math](y \rightsquigarrow z)[/math] и из вершины [math]x[/math] появилась дополняющая цепь.
Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из [math]x[/math] существовала и в исходном паросочетании.

Пусть [math]p[/math] - ближайшая к [math]x[/math] вершина, которая принадлежит и новой дополняющей цепи и цепи [math](y \rightsquigarrow z)[/math].
Тогда [math]MP[/math] - последнее ребро на отрезке [math](y \rightsquigarrow p)[/math] цепи [math](y \rightsquigarrow z)[/math], [math]NP[/math] - последнее ребро на отрезке [math](z \rightsquigarrow p)[/math] цепи [math](y \rightsquigarrow z)[/math], [math]QP[/math] - последнее ребро лежащее на отрезке [math](x \rightsquigarrow p)[/math] новой дополняющей цепи(см. Рисунок 1).

Допустим [math]MP[/math] принадлежит паросочетанию [math]M'[/math], тогда [math]NP[/math] ему не принадлежит.

Поскольку паросочетание [math]M'[/math] получается из [math]M[/math] изменением вдоль дополняющей цепи [math](y \rightsquigarrow z)[/math], в паросочетание [math]M[/math] входило ребро [math]NP[/math], а ребро [math]MP[/math] нет.
Кроме того, ребро [math]QP[/math] не лежит ни в исходном паросочетании [math]M[/math], ни в паросочетании [math]M'[/math], в противном случае оказалось бы, что вершина [math]p[/math] инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.

Тогда заметим, что цепь [math](x \rightsquigarrow z)[/math], полученная объединением цепей [math](x \rightsquigarrow p)[/math] и [math](p \rightsquigarrow z)[/math], по определению будет дополняющей в паросочетании [math]M[/math], что приводит к противоречию, поскольку в паросочетании [math]M[/math] из вершины [math]x[/math] не существует дополняющей цепи.
[math]\triangleleft[/math]

Алгоритм

Алгоритм Куна — непосредственное применение теоремы Бержа.

Алгоритм просматривает все вершины графа по очереди, запуская из каждой обход (в глубину или в ширину), пытающийся найти увеличивающую цепь, начинающуюся в этой вершине.
Краткое описание алгоритма:
  • Возьмём пустое паросочетание
  • Пока в графе удаётся найти увеличивающую цепь, выполняем чередование паросочетания вдоль этой цепи
  • Повторяем процесс поиска увеличивающей цепи.
  • Если увеличивающую цепь найти не удалось — процесс останавливается
  • Найденное паросочетание и является максимальным.


Будем считать, что граф уже разбит на две доли.
Просматриваем все вершины [math]v[/math] первой доли графа [math]v = 1 ... n_1[/math]:
  • Если текущая вершина уже насыщена текущим паросочетанием (т.е. уже выбрано какое-то смежное ей ребро), то эту вершину пропускаем
  • Иначе — алгоритм пытается насытить эту вершину, для чего запускается поиск увеличивающей цепи, начинающейся с этой вершины.


Рассмотрим поиск увеличивающей цепи обходом в глубину.
  • Изначально обход в глубину стоит в текущей ненасыщенной вершине [math]v[/math] первой доли.
  • Просматриваем все рёбра из этой вершины, пусть текущее ребро — [math](v, t_0)[/math].
  • Если вершина ещё не насыщена паросочетанием, то, значит, мы смогли найти увеличивающую цепь: она состоит из единственного ребра [math](v, t_0)[/math].
    • Включаем это ребро в паросочетание и прекращаем поиск увеличивающей цепи из вершины [math]v[/math].
    • Иначе, — если уже насыщена каким-то ребром [math](p, t_0)[/math], то попытаемся пройти вдоль этого ребра: тем самым мы попробуем найти увеличивающую цепь, проходящую через рёбра [math](v, t_0), (t_0, p)[/math]. Для этого просто перейдём в нашем обходе в вершину [math]p[/math].
      • Пробуем найти увеличивающую цепь из вершины [math]p[/math].
Этот обход, запущенный из вершины [math]v[/math], либо найдёт увеличивающую цепь, и тем самым насытит вершину, либо же такой увеличивающей цепи не найдёт (и, следовательно, эта вершина уже не сможет стать насыщенной).
После того, как все вершины [math]v = 1 ... n_1[/math] будут просмотрены, текущее паросочетание будет максимальным.

Релизация

Граф [math]G[/math] хранится списками смежности [math]g[][][/math]
Функция [math]dfs(v)[/math] - обход в глубину, возвращает [math]true[/math] если есть увеличивающая цепь из вершины [math]v[/math].
В массиве [math]mt[/math] хранятся паросочетания. Паросочетание есть ребро [math](i, mt[i])[/math].


bool dfs(int v) 
{
    if (used[v])
        return false;

    used[v] = true;
    for (int i = 0; i < g[v].size(); i++)
    {
        int to = g[v][i];
        if (mt[to] == -1 || dfs(mt[to]))
        {
            mt[to] = v;
            return true;
        }
    }
    return false;
}

int main()
{
    ... чтение графа ...
    mt.assign (k, -1);
    for (int v = 0; v < n; v++)
    {
        used.assign(n, false);
        dfs(v); 
    }

    for (int i = 0; i < k; i++)
        if (mt[i] != -1)
            ... вывод ...

}

Время работы

Итак, алгоритм Куна можно представить как серию из |[math]L[/math]| запусков обхода в глубину на всём графе.
Следовательно, всего этот алгоритм исполняется за время [math]O(V E)[/math], что в худшем случае есть [math]O(V^3)[/math].

Источники

MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания
Асанов М., Баранский В., Расин В. - Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство "Лань", 2010. — 291 стр.