<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Freemahn</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Freemahn"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/Freemahn"/>
		<updated>2026-05-19T16:37:26Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44161</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44161"/>
				<updated>2015-01-11T14:30:05Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Время работы */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|дополняющей цепи]] относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; – ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; – последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; – последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Задан граф &amp;lt;tex&amp;gt;G\langle V, E \rangle&amp;lt;/tex&amp;gt;, про который известно, что он двудольный, но разбиение не задано явно.Требуется найти наибольшее паросочетание в нем&lt;br /&gt;
&lt;br /&gt;
Алгоритм можно описать так: сначала возьмём пустое паросочетание, а потом — пока в графе удаётся найти увеличивающую цепь, — будем выполнять чередование паросочетания вдоль этой цепи, и повторять процесс поиска увеличивающей цепи. Как только такую цепь найти не удалось — процесс останавливаем, — текущее паросочетание и есть максимальное.&lt;br /&gt;
&lt;br /&gt;
В массиве &amp;lt;tex&amp;gt;\mathtt{matching}&amp;lt;/tex&amp;gt; хранятся паросочетания &amp;lt;tex&amp;gt; (v, \mathtt{matching}[v]) &amp;lt;/tex&amp;gt;  (Если паросочетания с вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; не существует, то &amp;lt;tex&amp;gt; \mathtt{matching}[v]= -1&amp;lt;/tex&amp;gt;). А &amp;lt;tex&amp;gt;used&amp;lt;/tex&amp;gt; — обычный массив &amp;quot;посещённостей&amp;quot; вершин в обходе в глубину (он нужен, чтобы обход в глубину не заходил в одну вершину дважды).&lt;br /&gt;
Функция &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; возвращает  &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если ей удалось найти увеличивающую цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, при этом считается, что эта функция уже произвела чередование паросочетания вдоль найденной цепи.&lt;br /&gt;
&lt;br /&gt;
Внутри функции просматриваются все рёбра, исходящие из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, и затем проверяется: если это ребро ведёт в ненасыщенную вершину &amp;lt;tex&amp;gt; to&amp;lt;/tex&amp;gt;, либо если эта вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; насыщена, но удаётся найти увеличивающую цепь рекурсивным запуском из &amp;lt;tex&amp;gt;\mathtt{matching}[to]&amp;lt;/tex&amp;gt;, то мы говорим, что мы нашли увеличивающую цепь, и перед возвратом из функции с результатом &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; производим чередование в текущем ребре: перенаправляем ребро, смежное с &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt;, в вершину &amp;lt;tex&amp;gt; v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В основной программе сначала указывается, что текущее паросочетание — пустое (массив &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt; заполняется числами &amp;lt;tex&amp;gt;-1&amp;lt;/tex&amp;gt;). Затем перебирается вершина  &amp;lt;tex&amp;gt;v &amp;lt;/tex&amp;gt;, и из неё запускается обход в глубину &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt;, предварительно обнулив массив &amp;lt;tex&amp;gt; used&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит заметить, что размер паросочетания легко получить как число вызовов &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; в основной программе, вернувших результат &amp;lt;tex&amp;gt; true &amp;lt;/tex&amp;gt;. Само искомое максимальное паросочетание содержится в массиве &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
После того, как все вершины &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G\langle V, E \rangle&amp;lt;/tex&amp;gt; хранится в матрице смежности &amp;lt;tex&amp;gt;g[i][j]&amp;lt;/tex&amp;gt; размера n  на n&lt;br /&gt;
&lt;br /&gt;
 '''bool''' dfs(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v])&lt;br /&gt;
         '''return''' ''false''&lt;br /&gt;
     used[v] = ''true''&lt;br /&gt;
     '''for''' to '''in''' g[v]&lt;br /&gt;
         '''if''' (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' ''true'' &lt;br /&gt;
     '''return''' ''false''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 function '''main'''():&lt;br /&gt;
     fill(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V&lt;br /&gt;
          fill(used, ''false'')&lt;br /&gt;
          dfs(v)&lt;br /&gt;
     '''for''' v '''in''' V&lt;br /&gt;
          '''if''' (matching[v] != -1)&lt;br /&gt;
               print(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44160</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44160"/>
				<updated>2015-01-11T14:29:31Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Реализация */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|дополняющей цепи]] относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; – ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; – последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; – последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Задан граф &amp;lt;tex&amp;gt;G\langle V, E \rangle&amp;lt;/tex&amp;gt;, про который известно, что он двудольный, но разбиение не задано явно.Требуется найти наибольшее паросочетание в нем&lt;br /&gt;
&lt;br /&gt;
Алгоритм можно описать так: сначала возьмём пустое паросочетание, а потом — пока в графе удаётся найти увеличивающую цепь, — будем выполнять чередование паросочетания вдоль этой цепи, и повторять процесс поиска увеличивающей цепи. Как только такую цепь найти не удалось — процесс останавливаем, — текущее паросочетание и есть максимальное.&lt;br /&gt;
&lt;br /&gt;
В массиве &amp;lt;tex&amp;gt;\mathtt{matching}&amp;lt;/tex&amp;gt; хранятся паросочетания &amp;lt;tex&amp;gt; (v, \mathtt{matching}[v]) &amp;lt;/tex&amp;gt;  (Если паросочетания с вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; не существует, то &amp;lt;tex&amp;gt; \mathtt{matching}[v]= -1&amp;lt;/tex&amp;gt;). А &amp;lt;tex&amp;gt;used&amp;lt;/tex&amp;gt; — обычный массив &amp;quot;посещённостей&amp;quot; вершин в обходе в глубину (он нужен, чтобы обход в глубину не заходил в одну вершину дважды).&lt;br /&gt;
Функция &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; возвращает  &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если ей удалось найти увеличивающую цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, при этом считается, что эта функция уже произвела чередование паросочетания вдоль найденной цепи.&lt;br /&gt;
&lt;br /&gt;
Внутри функции просматриваются все рёбра, исходящие из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, и затем проверяется: если это ребро ведёт в ненасыщенную вершину &amp;lt;tex&amp;gt; to&amp;lt;/tex&amp;gt;, либо если эта вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; насыщена, но удаётся найти увеличивающую цепь рекурсивным запуском из &amp;lt;tex&amp;gt;\mathtt{matching}[to]&amp;lt;/tex&amp;gt;, то мы говорим, что мы нашли увеличивающую цепь, и перед возвратом из функции с результатом &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; производим чередование в текущем ребре: перенаправляем ребро, смежное с &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt;, в вершину &amp;lt;tex&amp;gt; v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В основной программе сначала указывается, что текущее паросочетание — пустое (массив &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt; заполняется числами &amp;lt;tex&amp;gt;-1&amp;lt;/tex&amp;gt;). Затем перебирается вершина  &amp;lt;tex&amp;gt;v &amp;lt;/tex&amp;gt;, и из неё запускается обход в глубину &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt;, предварительно обнулив массив &amp;lt;tex&amp;gt; used&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит заметить, что размер паросочетания легко получить как число вызовов &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; в основной программе, вернувших результат &amp;lt;tex&amp;gt; true &amp;lt;/tex&amp;gt;. Само искомое максимальное паросочетание содержится в массиве &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
После того, как все вершины &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G\langle V, E \rangle&amp;lt;/tex&amp;gt; хранится в матрице смежности &amp;lt;tex&amp;gt;g[i][j]&amp;lt;/tex&amp;gt; размера n  на n&lt;br /&gt;
&lt;br /&gt;
 '''bool''' dfs(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v])&lt;br /&gt;
         '''return''' ''false''&lt;br /&gt;
     used[v] = ''true''&lt;br /&gt;
     '''for''' to '''in''' g[v]&lt;br /&gt;
         '''if''' (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' ''true'' &lt;br /&gt;
     '''return''' ''false''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 function '''main'''():&lt;br /&gt;
     fill(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V&lt;br /&gt;
          fill(used, ''false'')&lt;br /&gt;
          dfs(v)&lt;br /&gt;
     '''for''' v '''in''' V&lt;br /&gt;
          '''if''' (matching[v] != -1)&lt;br /&gt;
               print(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44159</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44159"/>
				<updated>2015-01-11T14:22:17Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Алгоритм */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|дополняющей цепи]] относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; – ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; – последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; – последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Задан граф &amp;lt;tex&amp;gt;G\langle V, E \rangle&amp;lt;/tex&amp;gt;, про который известно, что он двудольный, но разбиение не задано явно.Требуется найти наибольшее паросочетание в нем&lt;br /&gt;
&lt;br /&gt;
Алгоритм можно описать так: сначала возьмём пустое паросочетание, а потом — пока в графе удаётся найти увеличивающую цепь, — будем выполнять чередование паросочетания вдоль этой цепи, и повторять процесс поиска увеличивающей цепи. Как только такую цепь найти не удалось — процесс останавливаем, — текущее паросочетание и есть максимальное.&lt;br /&gt;
&lt;br /&gt;
В массиве &amp;lt;tex&amp;gt;\mathtt{matching}&amp;lt;/tex&amp;gt; хранятся паросочетания &amp;lt;tex&amp;gt; (v, \mathtt{matching}[v]) &amp;lt;/tex&amp;gt;  (Если паросочетания с вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; не существует, то &amp;lt;tex&amp;gt; \mathtt{matching}[v]= -1&amp;lt;/tex&amp;gt;). А &amp;lt;tex&amp;gt;used&amp;lt;/tex&amp;gt; — обычный массив &amp;quot;посещённостей&amp;quot; вершин в обходе в глубину (он нужен, чтобы обход в глубину не заходил в одну вершину дважды).&lt;br /&gt;
Функция &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; возвращает  &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если ей удалось найти увеличивающую цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, при этом считается, что эта функция уже произвела чередование паросочетания вдоль найденной цепи.&lt;br /&gt;
&lt;br /&gt;
Внутри функции просматриваются все рёбра, исходящие из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, и затем проверяется: если это ребро ведёт в ненасыщенную вершину &amp;lt;tex&amp;gt; to&amp;lt;/tex&amp;gt;, либо если эта вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; насыщена, но удаётся найти увеличивающую цепь рекурсивным запуском из &amp;lt;tex&amp;gt;\mathtt{matching}[to]&amp;lt;/tex&amp;gt;, то мы говорим, что мы нашли увеличивающую цепь, и перед возвратом из функции с результатом &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; производим чередование в текущем ребре: перенаправляем ребро, смежное с &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt;, в вершину &amp;lt;tex&amp;gt; v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В основной программе сначала указывается, что текущее паросочетание — пустое (массив &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt; заполняется числами &amp;lt;tex&amp;gt;-1&amp;lt;/tex&amp;gt;). Затем перебирается вершина  &amp;lt;tex&amp;gt;v &amp;lt;/tex&amp;gt;, и из неё запускается обход в глубину &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt;, предварительно обнулив массив &amp;lt;tex&amp;gt; used&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит заметить, что размер паросочетания легко получить как число вызовов &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; в основной программе, вернувших результат &amp;lt;tex&amp;gt; true &amp;lt;/tex&amp;gt;. Само искомое максимальное паросочетание содержится в массиве &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
После того, как все вершины &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится в матрице смежности &amp;lt;tex&amp;gt;g[I][j]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''bool''' dfs(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v])&lt;br /&gt;
         '''return''' ''false''&lt;br /&gt;
     used[v] = ''true''&lt;br /&gt;
     '''for''' to '''in''' g[v]&lt;br /&gt;
         '''if''' (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' ''true'' &lt;br /&gt;
     '''return''' ''false''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 function '''main'''():&lt;br /&gt;
     fill(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V&lt;br /&gt;
          fill(used, ''false'')&lt;br /&gt;
          dfs(v)&lt;br /&gt;
     '''for''' v '''in''' V&lt;br /&gt;
          '''if''' (matching[v] != -1)&lt;br /&gt;
               print(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44158</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44158"/>
				<updated>2015-01-11T14:19:50Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Алгоритм */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|дополняющей цепи]] относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; – ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; – последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; – последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Задан граф &amp;lt;tex&amp;gt;G\langle V, E \rangle&amp;lt;/tex&amp;gt;, про который известно, что он двудольный, но разбиение не задано явно.Требуется найти наибольшее паросочетание в нем&lt;br /&gt;
&lt;br /&gt;
Алгоритм можно описать так: сначала возьмём пустое паросочетание, а потом — пока в графе удаётся найти увеличивающую цепь, — будем выполнять чередование паросочетания вдоль этой цепи, и повторять процесс поиска увеличивающей цепи. Как только такую цепь найти не удалось — процесс останавливаем, — текущее паросочетание и есть максимальное.&lt;br /&gt;
&lt;br /&gt;
В массиве &amp;lt;tex&amp;gt;\mathtt{matching}&amp;lt;/tex&amp;gt; хранятся паросочетания &amp;lt;tex&amp;gt; (v, \mathtt{matching}[v]) &amp;lt;/tex&amp;gt;  (Если паросочетания с вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; не существует, то &amp;lt;tex&amp;gt; \mathtt{matching}[v]= -1&amp;lt;/tex&amp;gt;). А &amp;lt;tex&amp;gt;used&amp;lt;/tex&amp;gt; — обычный массив &amp;quot;посещённостей&amp;quot; вершин в обходе в глубину (он нужен, чтобы обход в глубину не заходил в одну вершину дважды).&lt;br /&gt;
Функция &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; возвращает  &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если ей удалось найти увеличивающую цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, при этом считается, что эта функция уже произвела чередование паросочетания вдоль найденной цепи.&lt;br /&gt;
&lt;br /&gt;
Внутри функции просматриваются все рёбра, исходящие из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли, и затем проверяется: если это ребро ведёт в ненасыщенную вершину &amp;lt;tex&amp;gt; to&amp;lt;/tex&amp;gt;, либо если эта вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; насыщена, но удаётся найти увеличивающую цепь рекурсивным запуском из &amp;lt;tex&amp;gt;\mathtt{matching}[to]&amp;lt;/tex&amp;gt;, то мы говорим, что мы нашли увеличивающую цепь, и перед возвратом из функции с результатом &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; производим чередование в текущем ребре: перенаправляем ребро, смежное с &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt;, в вершину &amp;lt;tex&amp;gt; v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В основной программе сначала указывается, что текущее паросочетание — пустое (массив &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt; заполняется числами &amp;lt;tex&amp;gt;-1&amp;lt;/tex&amp;gt;). Затем перебирается вершина  &amp;lt;tex&amp;gt;v &amp;lt;/tex&amp;gt; первой доли, и из неё запускается обход в глубину &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt;, предварительно обнулив массив &amp;lt;tex&amp;gt; used&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит заметить, что размер паросочетания легко получить как число вызовов &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; в основной программе, вернувших результат &amp;lt;tex&amp;gt; true &amp;lt;/tex&amp;gt;. Само искомое максимальное паросочетание содержится в массиве &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
После того, как все вершины &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится в матрице смежности &amp;lt;tex&amp;gt;g[I][j]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''bool''' dfs(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v])&lt;br /&gt;
         '''return''' ''false''&lt;br /&gt;
     used[v] = ''true''&lt;br /&gt;
     '''for''' to '''in''' g[v]&lt;br /&gt;
         '''if''' (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' ''true'' &lt;br /&gt;
     '''return''' ''false''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 function '''main'''():&lt;br /&gt;
     fill(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V&lt;br /&gt;
          fill(used, ''false'')&lt;br /&gt;
          dfs(v)&lt;br /&gt;
     '''for''' v '''in''' V&lt;br /&gt;
          '''if''' (matching[v] != -1)&lt;br /&gt;
               print(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44157</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44157"/>
				<updated>2015-01-11T14:18:54Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Теорема */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|дополняющей цепи]] относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; – ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; – последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; – последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Задан граф &amp;lt;tex&amp;gt;G\langle V, E \rangle&amp;lt;/tex&amp;gt;, про который известно, что он двудольный, но разбиение не задано явно.Требуется найти наибольшее паросочетание в нем&lt;br /&gt;
&lt;br /&gt;
Алгоритм можно описать так: сначала возьмём пустое паросочетание, а потом — пока в графе удаётся найти увеличивающую цепь, — будем выполнять чередование паросочетания вдоль этой цепи, и повторять процесс поиска увеличивающей цепи. Как только такую цепь найти не удалось — процесс останавливаем, — текущее паросочетание и есть максимальное.&lt;br /&gt;
&lt;br /&gt;
В массиве &amp;lt;tex&amp;gt;\mathtt{matching}&amp;lt;/tex&amp;gt; хранятся паросочетания &amp;lt;tex&amp;gt; (v, \mathtt{matching}[v]) &amp;lt;/tex&amp;gt;  (Если паросочетания с вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; не существует, то &amp;lt;tex&amp;gt; \mathtt{matching}[v]= -1&amp;lt;/tex&amp;gt;). А &amp;lt;tex&amp;gt;used&amp;lt;/tex&amp;gt; — обычный массив &amp;quot;посещённостей&amp;quot; вершин в обходе в глубину (он нужен, чтобы обход в глубину не заходил в одну вершину дважды).&lt;br /&gt;
Функция &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; возвращает  &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если ей удалось найти увеличивающую цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, при этом считается, что эта функция уже произвела чередование паросочетания вдоль найденной цепи.&lt;br /&gt;
&lt;br /&gt;
Внутри функции просматриваются все рёбра, исходящие из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли, и затем проверяется: если это ребро ведёт в ненасыщенную вершину &amp;lt;tex&amp;gt; to&amp;lt;/tex&amp;gt;, либо если эта вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; насыщена, но удаётся найти увеличивающую цепь рекурсивным запуском из &amp;lt;tex&amp;gt;\mathtt{matching}[to]&amp;lt;/tex&amp;gt;, то мы говорим, что мы нашли увеличивающую цепь, и перед возвратом из функции с результатом &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; производим чередование в текущем ребре: перенаправляем ребро, смежное с &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt;, в вершину &amp;lt;tex&amp;gt; v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В основной программе сначала указывается, что текущее паросочетание — пустое (массив &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt; заполняется числами -1). Затем перебирается вершина  &amp;lt;tex&amp;gt;v &amp;lt;/tex&amp;gt; первой доли, и из неё запускается обход в глубину &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt;, предварительно обнулив массив &amp;lt;tex&amp;gt; used&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит заметить, что размер паросочетания легко получить как число вызовов &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; в основной программе, вернувших результат &amp;lt;tex&amp;gt; true &amp;lt;/tex&amp;gt;. Само искомое максимальное паросочетание содержится в массиве &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
После того, как все вершины &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится в матрице смежности &amp;lt;tex&amp;gt;g[I][j]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''bool''' dfs(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v])&lt;br /&gt;
         '''return''' ''false''&lt;br /&gt;
     used[v] = ''true''&lt;br /&gt;
     '''for''' to '''in''' g[v]&lt;br /&gt;
         '''if''' (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' ''true'' &lt;br /&gt;
     '''return''' ''false''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 function '''main'''():&lt;br /&gt;
     fill(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V&lt;br /&gt;
          fill(used, ''false'')&lt;br /&gt;
          dfs(v)&lt;br /&gt;
     '''for''' v '''in''' V&lt;br /&gt;
          '''if''' (matching[v] != -1)&lt;br /&gt;
               print(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44156</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44156"/>
				<updated>2015-01-11T14:18:32Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Теорема */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|дополняющей цепи]] относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; – ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; – последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Задан граф &amp;lt;tex&amp;gt;G\langle V, E \rangle&amp;lt;/tex&amp;gt;, про который известно, что он двудольный, но разбиение не задано явно.Требуется найти наибольшее паросочетание в нем&lt;br /&gt;
&lt;br /&gt;
Алгоритм можно описать так: сначала возьмём пустое паросочетание, а потом — пока в графе удаётся найти увеличивающую цепь, — будем выполнять чередование паросочетания вдоль этой цепи, и повторять процесс поиска увеличивающей цепи. Как только такую цепь найти не удалось — процесс останавливаем, — текущее паросочетание и есть максимальное.&lt;br /&gt;
&lt;br /&gt;
В массиве &amp;lt;tex&amp;gt;\mathtt{matching}&amp;lt;/tex&amp;gt; хранятся паросочетания &amp;lt;tex&amp;gt; (v, \mathtt{matching}[v]) &amp;lt;/tex&amp;gt;  (Если паросочетания с вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; не существует, то &amp;lt;tex&amp;gt; \mathtt{matching}[v]= -1&amp;lt;/tex&amp;gt;). А &amp;lt;tex&amp;gt;used&amp;lt;/tex&amp;gt; — обычный массив &amp;quot;посещённостей&amp;quot; вершин в обходе в глубину (он нужен, чтобы обход в глубину не заходил в одну вершину дважды).&lt;br /&gt;
Функция &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; возвращает  &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если ей удалось найти увеличивающую цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, при этом считается, что эта функция уже произвела чередование паросочетания вдоль найденной цепи.&lt;br /&gt;
&lt;br /&gt;
Внутри функции просматриваются все рёбра, исходящие из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли, и затем проверяется: если это ребро ведёт в ненасыщенную вершину &amp;lt;tex&amp;gt; to&amp;lt;/tex&amp;gt;, либо если эта вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; насыщена, но удаётся найти увеличивающую цепь рекурсивным запуском из &amp;lt;tex&amp;gt;\mathtt{matching}[to]&amp;lt;/tex&amp;gt;, то мы говорим, что мы нашли увеличивающую цепь, и перед возвратом из функции с результатом &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; производим чередование в текущем ребре: перенаправляем ребро, смежное с &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt;, в вершину &amp;lt;tex&amp;gt; v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В основной программе сначала указывается, что текущее паросочетание — пустое (массив &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt; заполняется числами -1). Затем перебирается вершина  &amp;lt;tex&amp;gt;v &amp;lt;/tex&amp;gt; первой доли, и из неё запускается обход в глубину &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt;, предварительно обнулив массив &amp;lt;tex&amp;gt; used&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит заметить, что размер паросочетания легко получить как число вызовов &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; в основной программе, вернувших результат &amp;lt;tex&amp;gt; true &amp;lt;/tex&amp;gt;. Само искомое максимальное паросочетание содержится в массиве &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
После того, как все вершины &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится в матрице смежности &amp;lt;tex&amp;gt;g[I][j]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''bool''' dfs(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v])&lt;br /&gt;
         '''return''' ''false''&lt;br /&gt;
     used[v] = ''true''&lt;br /&gt;
     '''for''' to '''in''' g[v]&lt;br /&gt;
         '''if''' (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' ''true'' &lt;br /&gt;
     '''return''' ''false''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 function '''main'''():&lt;br /&gt;
     fill(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V&lt;br /&gt;
          fill(used, ''false'')&lt;br /&gt;
          dfs(v)&lt;br /&gt;
     '''for''' v '''in''' V&lt;br /&gt;
          '''if''' (matching[v] != -1)&lt;br /&gt;
               print(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44155</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44155"/>
				<updated>2015-01-11T14:17:36Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Источники */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|дополняющей цепи]] относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; – последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Задан граф &amp;lt;tex&amp;gt;G\langle V, E \rangle&amp;lt;/tex&amp;gt;, про который известно, что он двудольный, но разбиение не задано явно.Требуется найти наибольшее паросочетание в нем&lt;br /&gt;
&lt;br /&gt;
Алгоритм можно описать так: сначала возьмём пустое паросочетание, а потом — пока в графе удаётся найти увеличивающую цепь, — будем выполнять чередование паросочетания вдоль этой цепи, и повторять процесс поиска увеличивающей цепи. Как только такую цепь найти не удалось — процесс останавливаем, — текущее паросочетание и есть максимальное.&lt;br /&gt;
&lt;br /&gt;
В массиве &amp;lt;tex&amp;gt;\mathtt{matching}&amp;lt;/tex&amp;gt; хранятся паросочетания &amp;lt;tex&amp;gt; (v, \mathtt{matching}[v]) &amp;lt;/tex&amp;gt;  (Если паросочетания с вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; не существует, то &amp;lt;tex&amp;gt; \mathtt{matching}[v]= -1&amp;lt;/tex&amp;gt;). А &amp;lt;tex&amp;gt;used&amp;lt;/tex&amp;gt; — обычный массив &amp;quot;посещённостей&amp;quot; вершин в обходе в глубину (он нужен, чтобы обход в глубину не заходил в одну вершину дважды).&lt;br /&gt;
Функция &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; возвращает  &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если ей удалось найти увеличивающую цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, при этом считается, что эта функция уже произвела чередование паросочетания вдоль найденной цепи.&lt;br /&gt;
&lt;br /&gt;
Внутри функции просматриваются все рёбра, исходящие из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли, и затем проверяется: если это ребро ведёт в ненасыщенную вершину &amp;lt;tex&amp;gt; to&amp;lt;/tex&amp;gt;, либо если эта вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; насыщена, но удаётся найти увеличивающую цепь рекурсивным запуском из &amp;lt;tex&amp;gt;\mathtt{matching}[to]&amp;lt;/tex&amp;gt;, то мы говорим, что мы нашли увеличивающую цепь, и перед возвратом из функции с результатом &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; производим чередование в текущем ребре: перенаправляем ребро, смежное с &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt;, в вершину &amp;lt;tex&amp;gt; v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В основной программе сначала указывается, что текущее паросочетание — пустое (массив &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt; заполняется числами -1). Затем перебирается вершина  &amp;lt;tex&amp;gt;v &amp;lt;/tex&amp;gt; первой доли, и из неё запускается обход в глубину &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt;, предварительно обнулив массив &amp;lt;tex&amp;gt; used&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит заметить, что размер паросочетания легко получить как число вызовов &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; в основной программе, вернувших результат &amp;lt;tex&amp;gt; true &amp;lt;/tex&amp;gt;. Само искомое максимальное паросочетание содержится в массиве &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
После того, как все вершины &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится в матрице смежности &amp;lt;tex&amp;gt;g[I][j]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''bool''' dfs(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v])&lt;br /&gt;
         '''return''' ''false''&lt;br /&gt;
     used[v] = ''true''&lt;br /&gt;
     '''for''' to '''in''' g[v]&lt;br /&gt;
         '''if''' (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' ''true'' &lt;br /&gt;
     '''return''' ''false''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 function '''main'''():&lt;br /&gt;
     fill(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V&lt;br /&gt;
          fill(used, ''false'')&lt;br /&gt;
          dfs(v)&lt;br /&gt;
     '''for''' v '''in''' V&lt;br /&gt;
          '''if''' (matching[v] != -1)&lt;br /&gt;
               print(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44154</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44154"/>
				<updated>2015-01-11T14:15:20Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Реализация */ исправлено&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|дополняющей цепи]] относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; – последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Задан граф &amp;lt;tex&amp;gt;G\langle V, E \rangle&amp;lt;/tex&amp;gt;, про который известно, что он двудольный, но разбиение не задано явно.Требуется найти наибольшее паросочетание в нем&lt;br /&gt;
&lt;br /&gt;
Алгоритм можно описать так: сначала возьмём пустое паросочетание, а потом — пока в графе удаётся найти увеличивающую цепь, — будем выполнять чередование паросочетания вдоль этой цепи, и повторять процесс поиска увеличивающей цепи. Как только такую цепь найти не удалось — процесс останавливаем, — текущее паросочетание и есть максимальное.&lt;br /&gt;
&lt;br /&gt;
В массиве &amp;lt;tex&amp;gt;\mathtt{matching}&amp;lt;/tex&amp;gt; хранятся паросочетания &amp;lt;tex&amp;gt; (v, \mathtt{matching}[v]) &amp;lt;/tex&amp;gt;  (Если паросочетания с вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; не существует, то &amp;lt;tex&amp;gt; \mathtt{matching}[v]= -1&amp;lt;/tex&amp;gt;). А &amp;lt;tex&amp;gt;used&amp;lt;/tex&amp;gt; — обычный массив &amp;quot;посещённостей&amp;quot; вершин в обходе в глубину (он нужен, чтобы обход в глубину не заходил в одну вершину дважды).&lt;br /&gt;
Функция &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; возвращает  &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если ей удалось найти увеличивающую цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, при этом считается, что эта функция уже произвела чередование паросочетания вдоль найденной цепи.&lt;br /&gt;
&lt;br /&gt;
Внутри функции просматриваются все рёбра, исходящие из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли, и затем проверяется: если это ребро ведёт в ненасыщенную вершину &amp;lt;tex&amp;gt; to&amp;lt;/tex&amp;gt;, либо если эта вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; насыщена, но удаётся найти увеличивающую цепь рекурсивным запуском из &amp;lt;tex&amp;gt;\mathtt{matching}[to]&amp;lt;/tex&amp;gt;, то мы говорим, что мы нашли увеличивающую цепь, и перед возвратом из функции с результатом &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; производим чередование в текущем ребре: перенаправляем ребро, смежное с &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt;, в вершину &amp;lt;tex&amp;gt; v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В основной программе сначала указывается, что текущее паросочетание — пустое (массив &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt; заполняется числами -1). Затем перебирается вершина  &amp;lt;tex&amp;gt;v &amp;lt;/tex&amp;gt; первой доли, и из неё запускается обход в глубину &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt;, предварительно обнулив массив &amp;lt;tex&amp;gt; used&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит заметить, что размер паросочетания легко получить как число вызовов &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; в основной программе, вернувших результат &amp;lt;tex&amp;gt; true &amp;lt;/tex&amp;gt;. Само искомое максимальное паросочетание содержится в массиве &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
После того, как все вершины &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится в матрице смежности &amp;lt;tex&amp;gt;g[I][j]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''bool''' dfs(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v])&lt;br /&gt;
         '''return''' ''false''&lt;br /&gt;
     used[v] = ''true''&lt;br /&gt;
     '''for''' to '''in''' g[v]&lt;br /&gt;
         '''if''' (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' ''true'' &lt;br /&gt;
     '''return''' ''false''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 function '''main'''():&lt;br /&gt;
     fill(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V&lt;br /&gt;
          fill(used, ''false'')&lt;br /&gt;
          dfs(v)&lt;br /&gt;
     '''for''' v '''in''' V&lt;br /&gt;
          '''if''' (matching[v] != -1)&lt;br /&gt;
               print(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44153</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44153"/>
				<updated>2015-01-11T14:09:57Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Алгоритм */ поправил на \mathrm и дефис на тире&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|дополняющей цепи]] относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; – последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Задан граф &amp;lt;tex&amp;gt;G\langle V, E \rangle&amp;lt;/tex&amp;gt;, про который известно, что он двудольный, но разбиение не задано явно.Требуется найти наибольшее паросочетание в нем&lt;br /&gt;
&lt;br /&gt;
Алгоритм можно описать так: сначала возьмём пустое паросочетание, а потом — пока в графе удаётся найти увеличивающую цепь, — будем выполнять чередование паросочетания вдоль этой цепи, и повторять процесс поиска увеличивающей цепи. Как только такую цепь найти не удалось — процесс останавливаем, — текущее паросочетание и есть максимальное.&lt;br /&gt;
&lt;br /&gt;
В массиве &amp;lt;tex&amp;gt;\mathtt{matching}&amp;lt;/tex&amp;gt; хранятся паросочетания &amp;lt;tex&amp;gt; (v, \mathtt{matching}[v]) &amp;lt;/tex&amp;gt;  (Если паросочетания с вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; не существует, то &amp;lt;tex&amp;gt; \mathtt{matching}[v]= -1&amp;lt;/tex&amp;gt;). А &amp;lt;tex&amp;gt;used&amp;lt;/tex&amp;gt; — обычный массив &amp;quot;посещённостей&amp;quot; вершин в обходе в глубину (он нужен, чтобы обход в глубину не заходил в одну вершину дважды).&lt;br /&gt;
Функция &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; возвращает  &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если ей удалось найти увеличивающую цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, при этом считается, что эта функция уже произвела чередование паросочетания вдоль найденной цепи.&lt;br /&gt;
&lt;br /&gt;
Внутри функции просматриваются все рёбра, исходящие из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли, и затем проверяется: если это ребро ведёт в ненасыщенную вершину &amp;lt;tex&amp;gt; to&amp;lt;/tex&amp;gt;, либо если эта вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; насыщена, но удаётся найти увеличивающую цепь рекурсивным запуском из &amp;lt;tex&amp;gt;\mathtt{matching}[to]&amp;lt;/tex&amp;gt;, то мы говорим, что мы нашли увеличивающую цепь, и перед возвратом из функции с результатом &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; производим чередование в текущем ребре: перенаправляем ребро, смежное с &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt;, в вершину &amp;lt;tex&amp;gt; v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В основной программе сначала указывается, что текущее паросочетание — пустое (массив &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt; заполняется числами -1). Затем перебирается вершина  &amp;lt;tex&amp;gt;v &amp;lt;/tex&amp;gt; первой доли, и из неё запускается обход в глубину &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt;, предварительно обнулив массив &amp;lt;tex&amp;gt; used&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит заметить, что размер паросочетания легко получить как число вызовов &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; в основной программе, вернувших результат &amp;lt;tex&amp;gt; true &amp;lt;/tex&amp;gt;. Само искомое максимальное паросочетание содержится в массиве &amp;lt;tex&amp;gt; \mathtt{matching}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
После того, как все вершины &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится списками смежности &amp;lt;tex&amp;gt;g[v][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''bool''' '''dfs'''(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v]):&lt;br /&gt;
         '''return''' '''false'''&lt;br /&gt;
     used[v] = '''true''';&lt;br /&gt;
     '''for''' to '''in''' g[v]:&lt;br /&gt;
         if (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' '''true'''    &lt;br /&gt;
     '''return''' '''false'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 '''function''' '''main'''():&lt;br /&gt;
     '''fill'''(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          '''fill'''(used, '''false''')&lt;br /&gt;
          '''dfs'''(v)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          '''if''' (matching[v] != -1):&lt;br /&gt;
               '''print'''(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44152</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44152"/>
				<updated>2015-01-11T14:04:23Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Теорема */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|дополняющей цепи]] относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; – последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Задан граф &amp;lt;tex&amp;gt;G(V, E)&amp;lt;/tex&amp;gt;, про который известно, что он двудольный, но разбиение не задано явно.Требуется найти наибольшее паросочетание в нем&lt;br /&gt;
&lt;br /&gt;
Алгоритм можно описать так: сначала возьмём пустое паросочетание, а потом — пока в графе удаётся найти увеличивающую цепь, — будем выполнять чередование паросочетания вдоль этой цепи, и повторять процесс поиска увеличивающей цепи. Как только такую цепь найти не удалось — процесс останавливаем, — текущее паросочетание и есть максимальное.&lt;br /&gt;
&lt;br /&gt;
В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания &amp;lt;tex&amp;gt; (v, matching[v]) &amp;lt;/tex&amp;gt;  (Если паросочетания с вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; не существует, то &amp;lt;tex&amp;gt; matching[v] &amp;lt;/tex&amp;gt; = -1). А &amp;lt;tex&amp;gt;used&amp;lt;/tex&amp;gt; - обычный массив &amp;quot;посещённостей&amp;quot; вершин в обходе в глубину (он нужен, чтобы обход в глубину не заходил в одну вершину дважды).&lt;br /&gt;
Функция &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; возвращает  &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если ей удалось найти увеличивающую цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, при этом считается, что эта функция уже произвела чередование паросочетания вдоль найденной цепи.&lt;br /&gt;
&lt;br /&gt;
Внутри функции просматриваются все рёбра, исходящие из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли, и затем проверяется: если это ребро ведёт в ненасыщенную вершину &amp;lt;tex&amp;gt; to&amp;lt;/tex&amp;gt;, либо если эта вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; насыщена, но удаётся найти увеличивающую цепь рекурсивным запуском из &amp;lt;tex&amp;gt;matching[to]&amp;lt;/tex&amp;gt;, то мы говорим, что мы нашли увеличивающую цепь, и перед возвратом из функции с результатом &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; производим чередование в текущем ребре: перенаправляем ребро, смежное с &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt;, в вершину &amp;lt;tex&amp;gt; v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В основной программе сначала указывается, что текущее паросочетание — пустое (массив &amp;lt;tex&amp;gt; matching&amp;lt;/tex&amp;gt; заполняется числами -1). Затем перебирается вершина  &amp;lt;tex&amp;gt;v &amp;lt;/tex&amp;gt; первой доли, и из неё запускается обход в глубину &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt;, предварительно обнулив массив &amp;lt;tex&amp;gt; used&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит заметить, что размер паросочетания легко получить как число вызовов &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; в основной программе, вернувших результат &amp;lt;tex&amp;gt; true &amp;lt;/tex&amp;gt;. Само искомое максимальное паросочетание содержится в массиве &amp;lt;tex&amp;gt; matching&amp;lt;/tex&amp;gt;.&lt;br /&gt;
После того, как все вершины &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится списками смежности &amp;lt;tex&amp;gt;g[v][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''bool''' '''dfs'''(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v]):&lt;br /&gt;
         '''return''' '''false'''&lt;br /&gt;
     used[v] = '''true''';&lt;br /&gt;
     '''for''' to '''in''' g[v]:&lt;br /&gt;
         if (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' '''true'''    &lt;br /&gt;
     '''return''' '''false'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 '''function''' '''main'''():&lt;br /&gt;
     '''fill'''(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          '''fill'''(used, '''false''')&lt;br /&gt;
          '''dfs'''(v)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          '''if''' (matching[v] != -1):&lt;br /&gt;
               '''print'''(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44151</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44151"/>
				<updated>2015-01-11T13:59:50Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Теорема */ Изменил дефис на тире&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; – последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Задан граф &amp;lt;tex&amp;gt;G(V, E)&amp;lt;/tex&amp;gt;, про который известно, что он двудольный, но разбиение не задано явно.Требуется найти наибольшее паросочетание в нем&lt;br /&gt;
&lt;br /&gt;
Алгоритм можно описать так: сначала возьмём пустое паросочетание, а потом — пока в графе удаётся найти увеличивающую цепь, — будем выполнять чередование паросочетания вдоль этой цепи, и повторять процесс поиска увеличивающей цепи. Как только такую цепь найти не удалось — процесс останавливаем, — текущее паросочетание и есть максимальное.&lt;br /&gt;
&lt;br /&gt;
В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания &amp;lt;tex&amp;gt; (v, matching[v]) &amp;lt;/tex&amp;gt;  (Если паросочетания с вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; не существует, то &amp;lt;tex&amp;gt; matching[v] &amp;lt;/tex&amp;gt; = -1). А &amp;lt;tex&amp;gt;used&amp;lt;/tex&amp;gt; - обычный массив &amp;quot;посещённостей&amp;quot; вершин в обходе в глубину (он нужен, чтобы обход в глубину не заходил в одну вершину дважды).&lt;br /&gt;
Функция &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; возвращает  &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если ей удалось найти увеличивающую цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, при этом считается, что эта функция уже произвела чередование паросочетания вдоль найденной цепи.&lt;br /&gt;
&lt;br /&gt;
Внутри функции просматриваются все рёбра, исходящие из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли, и затем проверяется: если это ребро ведёт в ненасыщенную вершину &amp;lt;tex&amp;gt; to&amp;lt;/tex&amp;gt;, либо если эта вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; насыщена, но удаётся найти увеличивающую цепь рекурсивным запуском из &amp;lt;tex&amp;gt;matching[to]&amp;lt;/tex&amp;gt;, то мы говорим, что мы нашли увеличивающую цепь, и перед возвратом из функции с результатом &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; производим чередование в текущем ребре: перенаправляем ребро, смежное с &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt;, в вершину &amp;lt;tex&amp;gt; v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В основной программе сначала указывается, что текущее паросочетание — пустое (массив &amp;lt;tex&amp;gt; matching&amp;lt;/tex&amp;gt; заполняется числами -1). Затем перебирается вершина  &amp;lt;tex&amp;gt;v &amp;lt;/tex&amp;gt; первой доли, и из неё запускается обход в глубину &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt;, предварительно обнулив массив &amp;lt;tex&amp;gt; used&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит заметить, что размер паросочетания легко получить как число вызовов &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; в основной программе, вернувших результат &amp;lt;tex&amp;gt; true &amp;lt;/tex&amp;gt;. Само искомое максимальное паросочетание содержится в массиве &amp;lt;tex&amp;gt; matching&amp;lt;/tex&amp;gt;.&lt;br /&gt;
После того, как все вершины &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится списками смежности &amp;lt;tex&amp;gt;g[v][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''bool''' '''dfs'''(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v]):&lt;br /&gt;
         '''return''' '''false'''&lt;br /&gt;
     used[v] = '''true''';&lt;br /&gt;
     '''for''' to '''in''' g[v]:&lt;br /&gt;
         if (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' '''true'''    &lt;br /&gt;
     '''return''' '''false'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 '''function''' '''main'''():&lt;br /&gt;
     '''fill'''(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          '''fill'''(used, '''false''')&lt;br /&gt;
          '''dfs'''(v)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          '''if''' (matching[v] != -1):&lt;br /&gt;
               '''print'''(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44149</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44149"/>
				<updated>2015-01-11T13:32:05Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Алгоритм */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Задан граф &amp;lt;tex&amp;gt;G(V, E)&amp;lt;/tex&amp;gt;, про который известно, что он двудольный, но разбиение не задано явно.Требуется найти наибольшее паросочетание в нем&lt;br /&gt;
&lt;br /&gt;
Алгоритм можно описать так: сначала возьмём пустое паросочетание, а потом — пока в графе удаётся найти увеличивающую цепь, — будем выполнять чередование паросочетания вдоль этой цепи, и повторять процесс поиска увеличивающей цепи. Как только такую цепь найти не удалось — процесс останавливаем, — текущее паросочетание и есть максимальное.&lt;br /&gt;
&lt;br /&gt;
В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания &amp;lt;tex&amp;gt; (v, matching[v]) &amp;lt;/tex&amp;gt;  (Если паросочетания с вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; не существует, то &amp;lt;tex&amp;gt; matching[v] &amp;lt;/tex&amp;gt; = -1). А &amp;lt;tex&amp;gt;used&amp;lt;/tex&amp;gt; - обычный массив &amp;quot;посещённостей&amp;quot; вершин в обходе в глубину (он нужен, чтобы обход в глубину не заходил в одну вершину дважды).&lt;br /&gt;
Функция &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; возвращает  &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если ей удалось найти увеличивающую цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, при этом считается, что эта функция уже произвела чередование паросочетания вдоль найденной цепи.&lt;br /&gt;
&lt;br /&gt;
Внутри функции просматриваются все рёбра, исходящие из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли, и затем проверяется: если это ребро ведёт в ненасыщенную вершину &amp;lt;tex&amp;gt; to&amp;lt;/tex&amp;gt;, либо если эта вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; насыщена, но удаётся найти увеличивающую цепь рекурсивным запуском из &amp;lt;tex&amp;gt;matching[to]&amp;lt;/tex&amp;gt;, то мы говорим, что мы нашли увеличивающую цепь, и перед возвратом из функции с результатом &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; производим чередование в текущем ребре: перенаправляем ребро, смежное с &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt;, в вершину &amp;lt;tex&amp;gt; v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В основной программе сначала указывается, что текущее паросочетание — пустое (массив &amp;lt;tex&amp;gt; matching&amp;lt;/tex&amp;gt; заполняется числами -1). Затем перебирается вершина  &amp;lt;tex&amp;gt;v &amp;lt;/tex&amp;gt; первой доли, и из неё запускается обход в глубину &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt;, предварительно обнулив массив &amp;lt;tex&amp;gt; used&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит заметить, что размер паросочетания легко получить как число вызовов &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; в основной программе, вернувших результат &amp;lt;tex&amp;gt; true &amp;lt;/tex&amp;gt;. Само искомое максимальное паросочетание содержится в массиве &amp;lt;tex&amp;gt; matching&amp;lt;/tex&amp;gt;.&lt;br /&gt;
После того, как все вершины &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится списками смежности &amp;lt;tex&amp;gt;g[v][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''bool''' '''dfs'''(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v]):&lt;br /&gt;
         '''return''' '''false'''&lt;br /&gt;
     used[v] = '''true''';&lt;br /&gt;
     '''for''' to '''in''' g[v]:&lt;br /&gt;
         if (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' '''true'''    &lt;br /&gt;
     '''return''' '''false'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 '''function''' '''main'''():&lt;br /&gt;
     '''fill'''(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          '''fill'''(used, '''false''')&lt;br /&gt;
          '''dfs'''(v)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          '''if''' (matching[v] != -1):&lt;br /&gt;
               '''print'''(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44148</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44148"/>
				<updated>2015-01-11T13:30:34Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Реализация */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Задан граф &amp;lt;tex&amp;gt;G(V, E)&amp;lt;/tex&amp;gt;, про который известно, что он двудольный, но разбиение не задано явно.Требуется найти наибольшее паросочетание в нем&lt;br /&gt;
&lt;br /&gt;
Алгоритм можно описать так: сначала возьмём пустое паросочетание, а потом — пока в графе удаётся найти увеличивающую цепь, — будем выполнять чередование паросочетания вдоль этой цепи, и повторять процесс поиска увеличивающей цепи. Как только такую цепь найти не удалось — процесс останавливаем, — текущее паросочетание и есть максимальное.&lt;br /&gt;
&lt;br /&gt;
В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания &amp;lt;tex&amp;gt; (v, matching[v]) &amp;lt;/tex&amp;gt;  (Если паросочетания с вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; не существует, то &amp;lt;tex&amp;gt; matching[v] &amp;lt;/tex&amp;gt; = -1). А &amp;lt;tex&amp;gt;used&amp;lt;/tex&amp;gt; - обычный массив &amp;quot;посещённостей&amp;quot; вершин в обходе в глубину (он нужен, чтобы обход в глубину не заходил в одну вершину дважды).&lt;br /&gt;
Функция &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; возвращает  &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если ей удалось найти увеличивающую цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, при этом считается, что эта функция уже произвела чередование паросочетания вдоль найденной цепи.&lt;br /&gt;
&lt;br /&gt;
Внутри функции просматриваются все рёбра, исходящие из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли, и затем проверяется: если это ребро ведёт в ненасыщенную вершину &amp;lt;tex&amp;gt; to&amp;lt;/tex&amp;gt;, либо если эта вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; насыщена, но удаётся найти увеличивающую цепь рекурсивным запуском из &amp;lt;tex&amp;gt;mt[to]&amp;lt;/tex&amp;gt;, то мы говорим, что мы нашли увеличивающую цепь, и перед возвратом из функции с результатом &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; производим чередование в текущем ребре: перенаправляем ребро, смежное с &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt;, в вершину &amp;lt;tex&amp;gt; v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В основной программе сначала указывается, что текущее паросочетание — пустое (список &amp;lt;tex&amp;gt; mt&amp;lt;/tex&amp;gt; заполняется числами -1). Затем перебирается вершина  &amp;lt;tex&amp;gt;v &amp;lt;/tex&amp;gt; первой доли, и из неё запускается обход в глубину &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt;, предварительно обнулив массив &amp;lt;tex&amp;gt; used&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит заметить, что размер паросочетания легко получить как число вызовов &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; в основной программе, вернувших результат &amp;lt;tex&amp;gt; true &amp;lt;/tex&amp;gt;. Само искомое максимальное паросочетание содержится в массиве &amp;lt;tex&amp;gt; mt &amp;lt;/tex&amp;gt;.&lt;br /&gt;
После того, как все вершины &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится списками смежности &amp;lt;tex&amp;gt;g[v][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''bool''' '''dfs'''(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v]):&lt;br /&gt;
         '''return''' '''false'''&lt;br /&gt;
     used[v] = '''true''';&lt;br /&gt;
     '''for''' to '''in''' g[v]:&lt;br /&gt;
         if (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' '''true'''    &lt;br /&gt;
     '''return''' '''false'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 '''function''' '''main'''():&lt;br /&gt;
     '''fill'''(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          '''fill'''(used, '''false''')&lt;br /&gt;
          '''dfs'''(v)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          '''if''' (matching[v] != -1):&lt;br /&gt;
               '''print'''(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44147</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44147"/>
				<updated>2015-01-11T13:29:13Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Алгоритм */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Задан граф &amp;lt;tex&amp;gt;G(V, E)&amp;lt;/tex&amp;gt;, про который известно, что он двудольный, но разбиение не задано явно.Требуется найти наибольшее паросочетание в нем&lt;br /&gt;
&lt;br /&gt;
Алгоритм можно описать так: сначала возьмём пустое паросочетание, а потом — пока в графе удаётся найти увеличивающую цепь, — будем выполнять чередование паросочетания вдоль этой цепи, и повторять процесс поиска увеличивающей цепи. Как только такую цепь найти не удалось — процесс останавливаем, — текущее паросочетание и есть максимальное.&lt;br /&gt;
&lt;br /&gt;
В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания &amp;lt;tex&amp;gt; (v, matching[v]) &amp;lt;/tex&amp;gt;  (Если паросочетания с вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; не существует, то &amp;lt;tex&amp;gt; matching[v] &amp;lt;/tex&amp;gt; = -1). А &amp;lt;tex&amp;gt;used&amp;lt;/tex&amp;gt; - обычный массив &amp;quot;посещённостей&amp;quot; вершин в обходе в глубину (он нужен, чтобы обход в глубину не заходил в одну вершину дважды).&lt;br /&gt;
Функция &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; возвращает  &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если ей удалось найти увеличивающую цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, при этом считается, что эта функция уже произвела чередование паросочетания вдоль найденной цепи.&lt;br /&gt;
&lt;br /&gt;
Внутри функции просматриваются все рёбра, исходящие из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли, и затем проверяется: если это ребро ведёт в ненасыщенную вершину &amp;lt;tex&amp;gt; to&amp;lt;/tex&amp;gt;, либо если эта вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; насыщена, но удаётся найти увеличивающую цепь рекурсивным запуском из &amp;lt;tex&amp;gt;mt[to]&amp;lt;/tex&amp;gt;, то мы говорим, что мы нашли увеличивающую цепь, и перед возвратом из функции с результатом &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; производим чередование в текущем ребре: перенаправляем ребро, смежное с &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt;, в вершину &amp;lt;tex&amp;gt; v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В основной программе сначала указывается, что текущее паросочетание — пустое (список &amp;lt;tex&amp;gt; mt&amp;lt;/tex&amp;gt; заполняется числами -1). Затем перебирается вершина  &amp;lt;tex&amp;gt;v &amp;lt;/tex&amp;gt; первой доли, и из неё запускается обход в глубину &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt;, предварительно обнулив массив &amp;lt;tex&amp;gt; used&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит заметить, что размер паросочетания легко получить как число вызовов &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; в основной программе, вернувших результат &amp;lt;tex&amp;gt; true &amp;lt;/tex&amp;gt;. Само искомое максимальное паросочетание содержится в массиве &amp;lt;tex&amp;gt; mt &amp;lt;/tex&amp;gt;.&lt;br /&gt;
После того, как все вершины &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится списками смежности &amp;lt;tex&amp;gt;g[v][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
* Функция &amp;lt;tex&amp;gt;dfs(v)&amp;lt;/tex&amp;gt; {{---}} обход в глубину, возвращает &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если есть увеличивающая цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания. Паросочетание есть ребро &amp;lt;tex&amp;gt;(i, matching[i])&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 '''bool''' '''dfs'''(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v]):&lt;br /&gt;
         '''return''' '''false'''&lt;br /&gt;
     used[v] = '''true''';&lt;br /&gt;
     '''for''' to '''in''' g[v]:&lt;br /&gt;
         if (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' '''true'''    &lt;br /&gt;
     '''return''' '''false'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 '''function''' '''main'''():&lt;br /&gt;
     '''fill'''(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          fill(used, '''false''')&lt;br /&gt;
          '''dfs'''(v)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          '''if''' (matching[v] != -1):&lt;br /&gt;
               '''print'''(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44146</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44146"/>
				<updated>2015-01-11T13:27:21Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Алгоритм */ изменил алгоритм&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Задан граф &amp;lt;tex&amp;gt;G(V, E)&amp;lt;/tex&amp;gt;, про который известно, что он двудольный, но разбиение не задано явно.Требуется найти наибольшее паросочетание в нем&lt;br /&gt;
&lt;br /&gt;
Алгоритм можно описать так: сначала возьмём пустое паросочетание, а потом — пока в графе удаётся найти увеличивающую цепь, — будем выполнять чередование паросочетания вдоль этой цепи, и повторять процесс поиска увеличивающей цепи. Как только такую цепь найти не удалось — процесс останавливаем, — текущее паросочетание и есть максимальное.&lt;br /&gt;
&lt;br /&gt;
В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания &amp;lt;tex&amp;gt; (v, matching[v]) &amp;lt;/tex&amp;gt;  (Если паросочетания с вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; не существует, то &amp;lt;tex&amp;gt; matching[v] &amp;lt;/tex&amp;gt; = -1). А &amp;lt;tex&amp;gt;used&amp;lt;/tex&amp;gt; - обычный массив &amp;quot;посещённостей&amp;quot; вершин в обходе в глубину (он нужен, чтобы обход в глубину не заходил в одну вершину дважды).&lt;br /&gt;
Функция &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; возвращает  &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если ей удалось найти увеличивающую цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, при этом считается, что эта функция уже произвела чередование паросочетания вдоль найденной цепи.&lt;br /&gt;
&lt;br /&gt;
Внутри функции просматриваются все рёбра, исходящие из вершины v первой доли, и затем проверяется: если это ребро ведёт в ненасыщенную вершину &amp;lt;tex&amp;gt; to&amp;lt;/tex&amp;gt;, либо если эта вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; насыщена, но удаётся найти увеличивающую цепь рекурсивным запуском из &amp;lt;tex&amp;gt;mt[to]&amp;lt;/tex&amp;gt;, то мы говорим, что мы нашли увеличивающую цепь, и перед возвратом из функции с результатом &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; производим чередование в текущем ребре: перенаправляем ребро, смежное с &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt;, в вершину &amp;lt;tex&amp;gt; v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В основной программе сначала указывается, что текущее паросочетание — пустое (список &amp;lt;tex&amp;gt; mt&amp;lt;/tex&amp;gt; заполняется числами -1). Затем перебирается вершина  &amp;lt;tex&amp;gt;v &amp;lt;/tex&amp;gt; первой доли, и из неё запускается обход в глубину &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt;, предварительно обнулив массив &amp;lt;tex&amp;gt; used&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит заметить, что размер паросочетания легко получить как число вызовов &amp;lt;tex&amp;gt; \mathrm{dfs} &amp;lt;/tex&amp;gt; в основной программе, вернувших результат &amp;lt;tex&amp;gt; true &amp;lt;/tex&amp;gt;. Само искомое максимальное паросочетание содержится в массиве &amp;lt;tex&amp;gt; mt &amp;lt;/tex&amp;gt;.&lt;br /&gt;
После того, как все вершины &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится списками смежности &amp;lt;tex&amp;gt;g[v][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
* Функция &amp;lt;tex&amp;gt;dfs(v)&amp;lt;/tex&amp;gt; {{---}} обход в глубину, возвращает &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если есть увеличивающая цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания. Паросочетание есть ребро &amp;lt;tex&amp;gt;(i, matching[i])&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 '''bool''' '''dfs'''(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v]):&lt;br /&gt;
         '''return''' '''false'''&lt;br /&gt;
     used[v] = '''true''';&lt;br /&gt;
     '''for''' to '''in''' g[v]:&lt;br /&gt;
         if (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' '''true'''    &lt;br /&gt;
     '''return''' '''false'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 '''function''' '''main'''():&lt;br /&gt;
     '''fill'''(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          fill(used, '''false''')&lt;br /&gt;
          '''dfs'''(v)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          '''if''' (matching[v] != -1):&lt;br /&gt;
               '''print'''(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44139</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44139"/>
				<updated>2015-01-11T12:56:09Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Реализация */ маленькая правка&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
:Алгоритм просматривает все вершины графа по очереди, запуская из каждой обход (в глубину или в ширину), пытающийся найти увеличивающую цепь, начинающуюся в этой вершине.&lt;br /&gt;
:Задан двудольный граф &amp;lt;tex&amp;gt;G(V, E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;V_2&amp;lt;/tex&amp;gt; {{---}} его левая и правая доли соответственно. &lt;br /&gt;
:Просматриваем все вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли графа &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
:*Если текущая вершина  уже насыщена текущим паросочетанием (т.е. уже выбрано какое-то смежное ей ребро), то эту вершину пропускаем;&lt;br /&gt;
:*Иначе запускаем поиск увеличивающей цепи, начинающейся с этой вершины.&lt;br /&gt;
:Рассмотрим поиск увеличивающей цепи обходом в глубину.&lt;br /&gt;
:* Запускаем обход от вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Просматриваем все рёбра из этой вершины, пусть текущее ребро — &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; ещё не насыщена паросочетанием, то включаем ребро &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt; в паросочетание и прекращаем поиск из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Иначе, если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; уже насыщена каким-то ребром &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt; и не посещена, то просто перейдем в нашем обходе в вершину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Пробуем найти часть увеличивающей цепи из вершины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Если получилось, то удаляем из паросочетания ребро &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt;, а вместо него добавляем &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;&lt;br /&gt;
: Этот обход, запущенный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, либо найдет увеличивающую цепь, и тем самым насытит вершину, либо же такой увеличивающей цепи не найдёт (и, следовательно, эта вершина  уже не сможет стать насыщенной).&lt;br /&gt;
: После того, как все вершины &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
: Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится списками смежности &amp;lt;tex&amp;gt;g[v][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
* Функция &amp;lt;tex&amp;gt;dfs(v)&amp;lt;/tex&amp;gt; {{---}} обход в глубину, возвращает &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если есть увеличивающая цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания. Паросочетание есть ребро &amp;lt;tex&amp;gt;(i, matching[i])&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 '''bool''' '''dfs'''(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v]):&lt;br /&gt;
         '''return''' '''false'''&lt;br /&gt;
     used[v] = '''true''';&lt;br /&gt;
     '''for''' to '''in''' g[v]:&lt;br /&gt;
         if (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' '''true'''    &lt;br /&gt;
     '''return''' '''false'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 '''function''' '''main'''():&lt;br /&gt;
     '''fill'''(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          fill(used, '''false''')&lt;br /&gt;
          '''dfs'''(v)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          '''if''' (matching[v] != -1):&lt;br /&gt;
               '''print'''(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44138</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44138"/>
				<updated>2015-01-11T12:55:29Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Реализация */ закончил редактирование кода&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
:Алгоритм просматривает все вершины графа по очереди, запуская из каждой обход (в глубину или в ширину), пытающийся найти увеличивающую цепь, начинающуюся в этой вершине.&lt;br /&gt;
:Задан двудольный граф &amp;lt;tex&amp;gt;G(V, E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;V_2&amp;lt;/tex&amp;gt; {{---}} его левая и правая доли соответственно. &lt;br /&gt;
:Просматриваем все вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли графа &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
:*Если текущая вершина  уже насыщена текущим паросочетанием (т.е. уже выбрано какое-то смежное ей ребро), то эту вершину пропускаем;&lt;br /&gt;
:*Иначе запускаем поиск увеличивающей цепи, начинающейся с этой вершины.&lt;br /&gt;
:Рассмотрим поиск увеличивающей цепи обходом в глубину.&lt;br /&gt;
:* Запускаем обход от вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Просматриваем все рёбра из этой вершины, пусть текущее ребро — &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; ещё не насыщена паросочетанием, то включаем ребро &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt; в паросочетание и прекращаем поиск из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Иначе, если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; уже насыщена каким-то ребром &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt; и не посещена, то просто перейдем в нашем обходе в вершину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Пробуем найти часть увеличивающей цепи из вершины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Если получилось, то удаляем из паросочетания ребро &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt;, а вместо него добавляем &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;&lt;br /&gt;
: Этот обход, запущенный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, либо найдет увеличивающую цепь, и тем самым насытит вершину, либо же такой увеличивающей цепи не найдёт (и, следовательно, эта вершина  уже не сможет стать насыщенной).&lt;br /&gt;
: После того, как все вершины &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
: Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится списками смежности &amp;lt;tex&amp;gt;g[v][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
* Функция &amp;lt;tex&amp;gt;dfs(v)&amp;lt;/tex&amp;gt; {{---}} обход в глубину, возвращает &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt;, если есть увеличивающая цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания. Паросочетание есть ребро &amp;lt;tex&amp;gt;(i, matching[i])&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 '''bool''' '''dfs'''(v: '''int'''):&lt;br /&gt;
     '''if''' (used[v]):&lt;br /&gt;
         '''return''' '''false'''&lt;br /&gt;
     used[v] = '''true''';&lt;br /&gt;
     '''for''' to '''in''' g[v]:&lt;br /&gt;
         if (matching[to] == -1 '''or''' dfs(matching[to])):&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' '''true'''    &lt;br /&gt;
     '''return''' '''false'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 '''function''' '''main'''():&lt;br /&gt;
     '''fill'''(matching, -1)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          fill(used, false)&lt;br /&gt;
          '''dfs'''(v)&lt;br /&gt;
     '''for''' v '''in''' V:&lt;br /&gt;
          '''if''' (matching[v] != -1):&lt;br /&gt;
               '''print'''(v, &amp;quot; &amp;quot;, matching[v])&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44134</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44134"/>
				<updated>2015-01-11T12:45:23Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Реализация */ половина изменений&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
:Алгоритм просматривает все вершины графа по очереди, запуская из каждой обход (в глубину или в ширину), пытающийся найти увеличивающую цепь, начинающуюся в этой вершине.&lt;br /&gt;
:Задан двудольный граф &amp;lt;tex&amp;gt;G(V, E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;V_2&amp;lt;/tex&amp;gt; {{---}} его левая и правая доли соответственно. &lt;br /&gt;
:Просматриваем все вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли графа &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
:*Если текущая вершина  уже насыщена текущим паросочетанием (т.е. уже выбрано какое-то смежное ей ребро), то эту вершину пропускаем;&lt;br /&gt;
:*Иначе запускаем поиск увеличивающей цепи, начинающейся с этой вершины.&lt;br /&gt;
:Рассмотрим поиск увеличивающей цепи обходом в глубину.&lt;br /&gt;
:* Запускаем обход от вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Просматриваем все рёбра из этой вершины, пусть текущее ребро — &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; ещё не насыщена паросочетанием, то включаем ребро &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt; в паросочетание и прекращаем поиск из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Иначе, если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; уже насыщена каким-то ребром &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt; и не посещена, то просто перейдем в нашем обходе в вершину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Пробуем найти часть увеличивающей цепи из вершины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Если получилось, то удаляем из паросочетания ребро &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt;, а вместо него добавляем &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;&lt;br /&gt;
: Этот обход, запущенный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, либо найдет увеличивающую цепь, и тем самым насытит вершину, либо же такой увеличивающей цепи не найдёт (и, следовательно, эта вершина  уже не сможет стать насыщенной).&lt;br /&gt;
: После того, как все вершины &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
: Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
&lt;br /&gt;
* Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится списками смежности &amp;lt;tex&amp;gt;g[v][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
* Функция &amp;lt;tex&amp;gt;dfs(v)&amp;lt;/tex&amp;gt; {{---}} обход в глубину, возвращает &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; если есть увеличивающая цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания. Паросочетание есть ребро &amp;lt;tex&amp;gt;(i, matching[i])&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 '''bool''' '''dfs'''('''int''' v) &lt;br /&gt;
     '''if''' (used[v])&lt;br /&gt;
         return false&lt;br /&gt;
     used[v] = true;&lt;br /&gt;
     '''for''' to '''in''' g[v]:&lt;br /&gt;
         if (matching[to] == -1 || dfs(matching[to]))&lt;br /&gt;
             matching[to] = v&lt;br /&gt;
             '''return''' true    &lt;br /&gt;
     '''return''' false&lt;br /&gt;
&lt;br /&gt;
Как вызывать:&lt;br /&gt;
&lt;br /&gt;
fill(matching, -1)&lt;br /&gt;
'''for''' u '''in''' N:&lt;br /&gt;
     fill(used, false)&lt;br /&gt;
     '''dfs'''(u)&lt;br /&gt;
for (int i = 0; i &amp;lt; k; i++)&lt;br /&gt;
     if (matching[i] != -1)&lt;br /&gt;
          ... вывод ...*/&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44128</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44128"/>
				<updated>2015-01-11T12:22:46Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Источники */ изменил с : на *&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
:Алгоритм просматривает все вершины графа по очереди, запуская из каждой обход (в глубину или в ширину), пытающийся найти увеличивающую цепь, начинающуюся в этой вершине.&lt;br /&gt;
:Задан двудольный граф &amp;lt;tex&amp;gt;G(V, E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;V_2&amp;lt;/tex&amp;gt; {{---}} его левая и правая доли соответственно. &lt;br /&gt;
:Просматриваем все вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли графа &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
:*Если текущая вершина  уже насыщена текущим паросочетанием (т.е. уже выбрано какое-то смежное ей ребро), то эту вершину пропускаем;&lt;br /&gt;
:*Иначе запускаем поиск увеличивающей цепи, начинающейся с этой вершины.&lt;br /&gt;
:Рассмотрим поиск увеличивающей цепи обходом в глубину.&lt;br /&gt;
:* Запускаем обход от вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Просматриваем все рёбра из этой вершины, пусть текущее ребро — &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; ещё не насыщена паросочетанием, то включаем ребро &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt; в паросочетание и прекращаем поиск из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Иначе, если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; уже насыщена каким-то ребром &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt; и не посещена, то просто перейдем в нашем обходе в вершину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Пробуем найти часть увеличивающей цепи из вершины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Если получилось, то удаляем из паросочетания ребро &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt;, а вместо него добавляем &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;&lt;br /&gt;
: Этот обход, запущенный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, либо найдет увеличивающую цепь, и тем самым насытит вершину, либо же такой увеличивающей цепи не найдёт (и, следовательно, эта вершина  уже не сможет стать насыщенной).&lt;br /&gt;
: После того, как все вершины &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
: Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Релизация==&lt;br /&gt;
&lt;br /&gt;
: Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится списками смежности &amp;lt;tex&amp;gt;g[v][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
: Функция &amp;lt;tex&amp;gt;dfs(v)&amp;lt;/tex&amp;gt; {{---}} обход в глубину, возвращает &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; если есть увеличивающая цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания. Паросочетание есть ребро &amp;lt;tex&amp;gt;(i, matching[i])&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 bool dfs(int v) &lt;br /&gt;
 {&lt;br /&gt;
     if (used[v])&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     used[v] = true;&lt;br /&gt;
     for (int i = 0; i &amp;lt; g[v].size(); i++)&lt;br /&gt;
     {&lt;br /&gt;
         int to = g[v][i];&lt;br /&gt;
         if (matching[to] == -1 || dfs(matching[to]))&lt;br /&gt;
         {&lt;br /&gt;
             matching[to] = v;&lt;br /&gt;
             return true;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     return false;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int main()&lt;br /&gt;
 {&lt;br /&gt;
     ... чтение графа ...&lt;br /&gt;
     matching.assign (k, -1);&lt;br /&gt;
     for (int u = 0; u &amp;lt; n; u++)&lt;br /&gt;
     {&lt;br /&gt;
         used.assign(n, false);&lt;br /&gt;
         dfs(u); &lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int i = 0; i &amp;lt; k; i++)&lt;br /&gt;
         if (matching[i] != -1)&lt;br /&gt;
             ... вывод ...&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
*[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
* Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44127</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44127"/>
				<updated>2015-01-11T12:20:28Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Алгоритм */ исправил неправильное название теоремы&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
:Алгоритм просматривает все вершины графа по очереди, запуская из каждой обход (в глубину или в ширину), пытающийся найти увеличивающую цепь, начинающуюся в этой вершине.&lt;br /&gt;
:Задан двудольный граф &amp;lt;tex&amp;gt;G(V, E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;V_2&amp;lt;/tex&amp;gt; {{---}} его левая и правая доли соответственно. &lt;br /&gt;
:Просматриваем все вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли графа &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
:*Если текущая вершина  уже насыщена текущим паросочетанием (т.е. уже выбрано какое-то смежное ей ребро), то эту вершину пропускаем;&lt;br /&gt;
:*Иначе запускаем поиск увеличивающей цепи, начинающейся с этой вершины.&lt;br /&gt;
:Рассмотрим поиск увеличивающей цепи обходом в глубину.&lt;br /&gt;
:* Запускаем обход от вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Просматриваем все рёбра из этой вершины, пусть текущее ребро — &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; ещё не насыщена паросочетанием, то включаем ребро &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt; в паросочетание и прекращаем поиск из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Иначе, если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; уже насыщена каким-то ребром &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt; и не посещена, то просто перейдем в нашем обходе в вершину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Пробуем найти часть увеличивающей цепи из вершины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Если получилось, то удаляем из паросочетания ребро &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt;, а вместо него добавляем &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;&lt;br /&gt;
: Этот обход, запущенный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, либо найдет увеличивающую цепь, и тем самым насытит вершину, либо же такой увеличивающей цепи не найдёт (и, следовательно, эта вершина  уже не сможет стать насыщенной).&lt;br /&gt;
: После того, как все вершины &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
: Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы о максимальном паросочетании и дополняющих цепях]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Релизация==&lt;br /&gt;
&lt;br /&gt;
: Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится списками смежности &amp;lt;tex&amp;gt;g[v][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
: Функция &amp;lt;tex&amp;gt;dfs(v)&amp;lt;/tex&amp;gt; {{---}} обход в глубину, возвращает &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; если есть увеличивающая цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания. Паросочетание есть ребро &amp;lt;tex&amp;gt;(i, matching[i])&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 bool dfs(int v) &lt;br /&gt;
 {&lt;br /&gt;
     if (used[v])&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     used[v] = true;&lt;br /&gt;
     for (int i = 0; i &amp;lt; g[v].size(); i++)&lt;br /&gt;
     {&lt;br /&gt;
         int to = g[v][i];&lt;br /&gt;
         if (matching[to] == -1 || dfs(matching[to]))&lt;br /&gt;
         {&lt;br /&gt;
             matching[to] = v;&lt;br /&gt;
             return true;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     return false;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int main()&lt;br /&gt;
 {&lt;br /&gt;
     ... чтение графа ...&lt;br /&gt;
     matching.assign (k, -1);&lt;br /&gt;
     for (int u = 0; u &amp;lt; n; u++)&lt;br /&gt;
     {&lt;br /&gt;
         used.assign(n, false);&lt;br /&gt;
         dfs(u); &lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int i = 0; i &amp;lt; k; i++)&lt;br /&gt;
         if (matching[i] != -1)&lt;br /&gt;
             ... вывод ...&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
:[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
: Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44124</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44124"/>
				<updated>2015-01-11T12:13:00Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Алгоритм */ Убрал лишние пробелы(х2)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
:Алгоритм просматривает все вершины графа по очереди, запуская из каждой обход (в глубину или в ширину), пытающийся найти увеличивающую цепь, начинающуюся в этой вершине.&lt;br /&gt;
:Задан двудольный граф &amp;lt;tex&amp;gt;G(V, E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;V_2&amp;lt;/tex&amp;gt; {{---}} его левая и правая доли соответственно. &lt;br /&gt;
:Просматриваем все вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли графа &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
:*Если текущая вершина  уже насыщена текущим паросочетанием (т.е. уже выбрано какое-то смежное ей ребро), то эту вершину пропускаем;&lt;br /&gt;
:*Иначе запускаем поиск увеличивающей цепи, начинающейся с этой вершины.&lt;br /&gt;
:Рассмотрим поиск увеличивающей цепи обходом в глубину.&lt;br /&gt;
:* Запускаем обход от вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Просматриваем все рёбра из этой вершины, пусть текущее ребро — &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; ещё не насыщена паросочетанием, то включаем ребро &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt; в паросочетание и прекращаем поиск из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Иначе, если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; уже насыщена каким-то ребром &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt; и не посещена, то просто перейдем в нашем обходе в вершину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Пробуем найти часть увеличивающей цепи из вершины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Если получилось, то удаляем из паросочетания ребро &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt;, а вместо него добавляем &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;&lt;br /&gt;
: Этот обход, запущенный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, либо найдет увеличивающую цепь, и тем самым насытит вершину, либо же такой увеличивающей цепи не найдёт (и, следовательно, эта вершина  уже не сможет стать насыщенной).&lt;br /&gt;
: После того, как все вершины &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
: Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы Бержа]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Релизация==&lt;br /&gt;
&lt;br /&gt;
: Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится списками смежности &amp;lt;tex&amp;gt;g[v][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
: Функция &amp;lt;tex&amp;gt;dfs(v)&amp;lt;/tex&amp;gt; {{---}} обход в глубину, возвращает &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; если есть увеличивающая цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания. Паросочетание есть ребро &amp;lt;tex&amp;gt;(i, matching[i])&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 bool dfs(int v) &lt;br /&gt;
 {&lt;br /&gt;
     if (used[v])&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     used[v] = true;&lt;br /&gt;
     for (int i = 0; i &amp;lt; g[v].size(); i++)&lt;br /&gt;
     {&lt;br /&gt;
         int to = g[v][i];&lt;br /&gt;
         if (matching[to] == -1 || dfs(matching[to]))&lt;br /&gt;
         {&lt;br /&gt;
             matching[to] = v;&lt;br /&gt;
             return true;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     return false;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int main()&lt;br /&gt;
 {&lt;br /&gt;
     ... чтение графа ...&lt;br /&gt;
     matching.assign (k, -1);&lt;br /&gt;
     for (int u = 0; u &amp;lt; n; u++)&lt;br /&gt;
     {&lt;br /&gt;
         used.assign(n, false);&lt;br /&gt;
         dfs(u); &lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int i = 0; i &amp;lt; k; i++)&lt;br /&gt;
         if (matching[i] != -1)&lt;br /&gt;
             ... вывод ...&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
:[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
: Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44123</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44123"/>
				<updated>2015-01-11T12:06:38Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Алгоритм */ Убрал лишние пробелы(х2)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
:Алгоритм просматривает все вершины графа по очереди, запуская из каждой обход (в глубину или в ширину), пытающийся найти увеличивающую цепь, начинающуюся в этой вершине.&lt;br /&gt;
:Задан двудольный граф &amp;lt;tex&amp;gt;G(V, E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;V_2&amp;lt;/tex&amp;gt; {{---}} его левая и правая доли соответственно. &lt;br /&gt;
:Просматриваем все вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли графа &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
:*Если текущая вершина  уже насыщена текущим паросочетанием (т.е. уже выбрано какое-то смежное ей ребро), то эту вершину пропускаем;&lt;br /&gt;
:*Иначе запускаем поиск увеличивающей цепи, начинающейся с этой вершины.&lt;br /&gt;
:Рассмотрим поиск увеличивающей цепи обходом в глубину.&lt;br /&gt;
:* Запускаем обход от вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Просматриваем все рёбра из этой вершины, пусть текущее ребро — &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; ещё не насыщена паросочетанием, то включаем ребро &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt; в паросочетание и прекращаем поиск из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Иначе, если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; уже насыщена каким-то ребром &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt; и не посещена, то просто перейдем в нашем обходе в вершину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Пробуем найти часть увеличивающей цепи из вершины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Если получилось, то удаляем из паросочетания ребро &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt;, а вместо него добавляем &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Этот обход, запущенный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, либо найдет увеличивающую цепь, и тем самым насытит вершину, либо же такой увеличивающей цепи не найдёт (и, следовательно, эта вершина  уже не сможет стать насыщенной).&lt;br /&gt;
: После того, как все вершины &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
: Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы Бержа]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Релизация==&lt;br /&gt;
&lt;br /&gt;
: Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится списками смежности &amp;lt;tex&amp;gt;g[v][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
: Функция &amp;lt;tex&amp;gt;dfs(v)&amp;lt;/tex&amp;gt; {{---}} обход в глубину, возвращает &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; если есть увеличивающая цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания. Паросочетание есть ребро &amp;lt;tex&amp;gt;(i, matching[i])&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 bool dfs(int v) &lt;br /&gt;
 {&lt;br /&gt;
     if (used[v])&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     used[v] = true;&lt;br /&gt;
     for (int i = 0; i &amp;lt; g[v].size(); i++)&lt;br /&gt;
     {&lt;br /&gt;
         int to = g[v][i];&lt;br /&gt;
         if (matching[to] == -1 || dfs(matching[to]))&lt;br /&gt;
         {&lt;br /&gt;
             matching[to] = v;&lt;br /&gt;
             return true;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     return false;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int main()&lt;br /&gt;
 {&lt;br /&gt;
     ... чтение графа ...&lt;br /&gt;
     matching.assign (k, -1);&lt;br /&gt;
     for (int u = 0; u &amp;lt; n; u++)&lt;br /&gt;
     {&lt;br /&gt;
         used.assign(n, false);&lt;br /&gt;
         dfs(u); &lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int i = 0; i &amp;lt; k; i++)&lt;br /&gt;
         if (matching[i] != -1)&lt;br /&gt;
             ... вывод ...&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
:[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
: Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44122</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44122"/>
				<updated>2015-01-11T12:06:03Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Алгоритм */ убрал лишние пробелы&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
:Алгоритм просматривает все вершины графа по очереди, запуская из каждой обход (в глубину или в ширину), пытающийся найти увеличивающую цепь, начинающуюся в этой вершине.&lt;br /&gt;
:Задан двудольный граф &amp;lt;tex&amp;gt;G(V, E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;V_2&amp;lt;/tex&amp;gt; {{---}} его левая и правая доли соответственно. &lt;br /&gt;
:Просматриваем все вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли графа &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
:*Если текущая вершина  уже насыщена текущим паросочетанием (т.е. уже выбрано какое-то смежное ей ребро), то эту вершину пропускаем;&lt;br /&gt;
:*Иначе запускаем поиск увеличивающей цепи, начинающейся с этой вершины.&lt;br /&gt;
:Рассмотрим поиск увеличивающей цепи обходом в глубину.&lt;br /&gt;
:* Запускаем обход от вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Просматриваем все рёбра из этой вершины, пусть текущее ребро — &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; ещё не насыщена паросочетанием, то включаем ребро &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt; в паросочетание и прекращаем поиск из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Иначе, если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; уже насыщена каким-то ребром &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt; и не посещена, то просто перейдем в нашем обходе в вершину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Пробуем найти часть увеличивающей цепи из вершины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Если получилось, то удаляем из паросочетания ребро &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt;, а вместо него добавляем &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Этот обход, запущенный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, либо найдет увеличивающую цепь, и тем самым насытит вершину, либо же такой увеличивающей цепи не найдёт (и, следовательно, эта вершина  уже не сможет стать насыщенной).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: После того, как все вершины &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
: Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы Бержа]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Релизация==&lt;br /&gt;
&lt;br /&gt;
: Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится списками смежности &amp;lt;tex&amp;gt;g[v][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
: Функция &amp;lt;tex&amp;gt;dfs(v)&amp;lt;/tex&amp;gt; {{---}} обход в глубину, возвращает &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; если есть увеличивающая цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания. Паросочетание есть ребро &amp;lt;tex&amp;gt;(i, matching[i])&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 bool dfs(int v) &lt;br /&gt;
 {&lt;br /&gt;
     if (used[v])&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     used[v] = true;&lt;br /&gt;
     for (int i = 0; i &amp;lt; g[v].size(); i++)&lt;br /&gt;
     {&lt;br /&gt;
         int to = g[v][i];&lt;br /&gt;
         if (matching[to] == -1 || dfs(matching[to]))&lt;br /&gt;
         {&lt;br /&gt;
             matching[to] = v;&lt;br /&gt;
             return true;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     return false;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int main()&lt;br /&gt;
 {&lt;br /&gt;
     ... чтение графа ...&lt;br /&gt;
     matching.assign (k, -1);&lt;br /&gt;
     for (int u = 0; u &amp;lt; n; u++)&lt;br /&gt;
     {&lt;br /&gt;
         used.assign(n, false);&lt;br /&gt;
         dfs(u); &lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int i = 0; i &amp;lt; k; i++)&lt;br /&gt;
         if (matching[i] != -1)&lt;br /&gt;
             ... вывод ...&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
:[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
: Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44121</id>
		<title>Алгоритм Куна для поиска максимального паросочетания</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D1%83%D0%BD%D0%B0_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%B0%D1%80%D0%BE%D1%81%D0%BE%D1%87%D0%B5%D1%82%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=44121"/>
				<updated>2015-01-11T12:05:20Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: /* Время работы */ Убрал лишние пробелы&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Теорема==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
 Если из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи относительно паросочетания &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; и паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи, тогда из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи в &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
[[Файл:Kuhn2.png|thumb|right|300x300px|Рисунок 1.]]&lt;br /&gt;
[[Файл:Kuhn1.png|thumb|right|300x300px|Рисунок 2.&amp;lt;br&amp;gt;Пунктиром обозначен путь между двумя вершинами. Ребро красного цвета лежит в паросочетании, а черного - нет.]]&lt;br /&gt;
: Доказательство от противного.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим в паросочетание внесли изменения вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt; и из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; появилась дополняющая цепь.&lt;br /&gt;
: Заметим, что эта дополняющая цепь должна вершинно пересекаться с той цепью, вдоль которой вносились изменения, иначе такая же дополняющая цепь из &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; существовала и в исходном паросочетании.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Пусть &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} ближайшая к &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; вершина, которая принадлежит и новой дополняющей цепи и цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Тогда &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(y \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; - последнее ребро на отрезке &amp;lt;tex&amp;gt;(z \rightsquigarrow p)&amp;lt;/tex&amp;gt; цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; - последнее ребро лежащее на отрезке &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; новой дополняющей цепи(см. Рисунок 1).&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Допустим &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; ему не принадлежит.&amp;lt;br&amp;gt;&lt;br /&gt;
:: (Случай, когда &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt; принадлежит паросочетанию &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; полностью симметричен.)&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
: Поскольку паросочетание &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt; получается из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; изменением вдоль дополняющей цепи &amp;lt;tex&amp;gt;(y \rightsquigarrow z)&amp;lt;/tex&amp;gt;, в паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; входило ребро &amp;lt;tex&amp;gt;NP&amp;lt;/tex&amp;gt;, а ребро &amp;lt;tex&amp;gt;MP&amp;lt;/tex&amp;gt; нет.&lt;br /&gt;
: Кроме того, ребро &amp;lt;tex&amp;gt;QP&amp;lt;/tex&amp;gt; не лежит ни в исходном паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, ни в паросочетании &amp;lt;tex&amp;gt;M'&amp;lt;/tex&amp;gt;, в противном случае оказалось бы, что вершина &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; инцидентна нескольким ребрам из паросочетания, что противоречит определению паросочетания.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
:Тогда заметим, что цепь &amp;lt;tex&amp;gt;(x \rightsquigarrow z)&amp;lt;/tex&amp;gt;, полученная объединением цепей &amp;lt;tex&amp;gt;(x \rightsquigarrow p)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(p \rightsquigarrow z)&amp;lt;/tex&amp;gt;, по определению будет дополняющей в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, что приводит к противоречию, поскольку в паросочетании &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; из вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; не существует дополняющей цепи.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
:Алгоритм просматривает все вершины графа по очереди, запуская из каждой обход (в глубину или в ширину), пытающийся найти увеличивающую цепь, начинающуюся в этой вершине.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:Задан двудольный граф &amp;lt;tex&amp;gt;G(V, E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;V_2&amp;lt;/tex&amp;gt; {{---}} его левая и правая доли соответственно. &lt;br /&gt;
:Просматриваем все вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; первой доли графа &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
:*Если текущая вершина  уже насыщена текущим паросочетанием (т.е. уже выбрано какое-то смежное ей ребро), то эту вершину пропускаем;&lt;br /&gt;
:*Иначе запускаем поиск увеличивающей цепи, начинающейся с этой вершины.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:Рассмотрим поиск увеличивающей цепи обходом в глубину.&lt;br /&gt;
:* Запускаем обход от вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Просматриваем все рёбра из этой вершины, пусть текущее ребро — &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; ещё не насыщена паросочетанием, то включаем ребро &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt; в паросочетание и прекращаем поиск из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:* Иначе, если вершина &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; уже насыщена каким-то ребром &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt; и не посещена, то просто перейдем в нашем обходе в вершину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Пробуем найти часть увеличивающей цепи из вершины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:** Если получилось, то удаляем из паросочетания ребро &amp;lt;tex&amp;gt;(p, to)&amp;lt;/tex&amp;gt;, а вместо него добавляем &amp;lt;tex&amp;gt;(v, to)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Этот обход, запущенный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, либо найдет увеличивающую цепь, и тем самым насытит вершину, либо же такой увеличивающей цепи не найдёт (и, следовательно, эта вершина  уже не сможет стать насыщенной).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: После того, как все вершины &amp;lt;tex&amp;gt;u \in V_1&amp;lt;/tex&amp;gt; будут просмотрены, текущее паросочетание будет максимальным.&lt;br /&gt;
: Корректность алгоритма следует из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы Бержа]] и теоремы, описанной выше.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Релизация==&lt;br /&gt;
&lt;br /&gt;
: Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; хранится списками смежности &amp;lt;tex&amp;gt;g[v][i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
: Функция &amp;lt;tex&amp;gt;dfs(v)&amp;lt;/tex&amp;gt; {{---}} обход в глубину, возвращает &amp;lt;tex&amp;gt;true&amp;lt;/tex&amp;gt; если есть увеличивающая цепь из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: В массиве &amp;lt;tex&amp;gt;matching&amp;lt;/tex&amp;gt; хранятся паросочетания. Паросочетание есть ребро &amp;lt;tex&amp;gt;(i, matching[i])&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 bool dfs(int v) &lt;br /&gt;
 {&lt;br /&gt;
     if (used[v])&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     used[v] = true;&lt;br /&gt;
     for (int i = 0; i &amp;lt; g[v].size(); i++)&lt;br /&gt;
     {&lt;br /&gt;
         int to = g[v][i];&lt;br /&gt;
         if (matching[to] == -1 || dfs(matching[to]))&lt;br /&gt;
         {&lt;br /&gt;
             matching[to] = v;&lt;br /&gt;
             return true;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     return false;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int main()&lt;br /&gt;
 {&lt;br /&gt;
     ... чтение графа ...&lt;br /&gt;
     matching.assign (k, -1);&lt;br /&gt;
     for (int u = 0; u &amp;lt; n; u++)&lt;br /&gt;
     {&lt;br /&gt;
         used.assign(n, false);&lt;br /&gt;
         dfs(u); &lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for (int i = 0; i &amp;lt; k; i++)&lt;br /&gt;
         if (matching[i] != -1)&lt;br /&gt;
             ... вывод ...&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
:Итак, алгоритм Куна можно представить как серию из  &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; запусков обхода в глубину на всём графе.&lt;br /&gt;
:Следовательно, всего этот алгоритм исполняется за время &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество ребер, что в худшем случае есть &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:Более точная оценка:&lt;br /&gt;
:В описанной выше реализации запуски обхода в глубину/ширину происходят только из вершин первой доли, поэтому весь алгоритм исполняется за время &amp;lt;tex&amp;gt;O(n_1m)&amp;lt;/tex&amp;gt; , где &amp;lt;tex&amp;gt;n_1&amp;lt;/tex&amp;gt; — число вершин первой доли. В худшем случае это составляет &amp;lt;tex&amp;gt;O(n_1^2n_2)&amp;lt;/tex&amp;gt;,  где &amp;lt;tex&amp;gt;n_2&amp;lt;/tex&amp;gt; — число вершин второй доли.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм Форда-Фалкерсона для поиска максимального паросочетания|Алгоритм Форда-Фалкерсона для поиска максимального паросочетания]]&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
:[http://e-maxx.ru/algo/kuhn_matching MAXimal :: algo :: Алгоритм Куна нахождения наибольшего паросочетания]&amp;lt;br&amp;gt;&lt;br /&gt;
: Асанов М., Баранский В., Расин В. {{---}} Дискретная математика: Графы, матроиды, алгоритмы — СПб.: Издательство &amp;quot;Лань&amp;quot;, 2010. — 291 стр.&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D1%81%D0%B8%D0%BC%D0%B2%D0%BE%D0%BB%D0%BE%D0%B2,_%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D1%8B_%D0%BA%D0%BE%D0%B4%D0%B8%D1%80%D0%BE%D0%B2%D0%BE%D0%BA&amp;diff=35132</id>
		<title>Представление символов, таблицы кодировок</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D1%81%D0%B8%D0%BC%D0%B2%D0%BE%D0%BB%D0%BE%D0%B2,_%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D1%8B_%D0%BA%D0%BE%D0%B4%D0%B8%D1%80%D0%BE%D0%B2%D0%BE%D0%BA&amp;diff=35132"/>
				<updated>2014-01-05T13:39:00Z</updated>
		
		<summary type="html">&lt;p&gt;Freemahn: Добавил пример на python и hex-дамп&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Представление символов в вычислительных машинах ==&lt;br /&gt;
&lt;br /&gt;
В вычислительных машинах символы не могут храниться иначе, как в виде последовательностей битов (как и числа). Для передачи символа и его корректного отображения ему должна соответствовать уникальная последовательность нулей и единиц. Для этого были разработаны таблицы кодировок.&lt;br /&gt;
&lt;br /&gt;
Количество символов, которые можно задать последовательностью битов длины ''n'', задается простой формулой &amp;lt;tex&amp;gt;C(n) = 2^n&amp;lt;/tex&amp;gt;. Таким образом, от нужного количества символов напрямую зависит количество используемой памяти.&lt;br /&gt;
&lt;br /&gt;
== Таблицы кодировок ==&lt;br /&gt;
&lt;br /&gt;
На заре компьютерной эры на каждый символ было отведено по 5 бит. Это было связано с малым количеством оперативной памяти на компьютерах тех лет. В эти 64 символа входили только управляющие символы и строчные буквы английского алфавита.&lt;br /&gt;
&lt;br /&gt;
С ростом производительности компьютеров стали появляться таблицы кодировок с большим количеством символов.&lt;br /&gt;
Первой 7 битной кодировкой стала ASCII7. В нее уже вошли прописные буквы английского алфавита, арабские цифры, знаки препинания.&lt;br /&gt;
Затем на ее базе была разработана ASCII8, в которым уже стало возможным хранение 256 символов: 128 основных и еще столько же расширенных. Первая часть таблицы осталась без изменений, а вторая может иметь различные варианты (каждый имеет свой номер). Эта часть таблицы стала заполняться символами национальных алфавитов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Но для многих языков (например, арабского, японского, китайского) 256 символов недостаточно, поэтому развитие кодировок продолжалось, что привело к появлению UNICODE.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Наиболее известные кодировки ==&lt;br /&gt;
===Кодировки стандарта ASCII===&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition='''ASCII''' - таблицы кодировок, в которых содержатся основные символы (английский алфавит, цифры, знаки препинания, символы национальных алфавитов(свои для каждого региона), служебные символы) и длина кода каждого символа &amp;lt;tex&amp;gt;n = 8&amp;lt;/tex&amp;gt; бит.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
''7 бит:''&lt;br /&gt;
* '''ASCII7''' - первая кодировка, пригодная для работы с текстом. Помимо маленьких букв английского алфавита и служебных символов, содержит большие буквы английского языка, цифры, знаки препинания и другие символы.&lt;br /&gt;
''Кодировки стандарта ASCII (8 бит):''&lt;br /&gt;
* '''ASCII''' - первая кодировка, в которой стало возможно использовать символы национальных алфавитов.&lt;br /&gt;
* '''КОИ8-R''' - первая русская кодировка. Символы кириллицы расположены не в алфавитном порядке. Их разместили в верхнюю половину таблицы так, чтобы позиции кириллических символов соответствовали их фонетическим аналогам в английском алфавите. Это значит, что даже при потере старшего бита каждого символа, например, при проходе через устаревший семибитный модем, текст остается &amp;quot;читаемым&amp;quot;.&lt;br /&gt;
* '''CP866''' - русская кодировка, использовавшаяся на компьютерах IBM в системе DOS.&lt;br /&gt;
* '''Windows-1251''' - русская кодировка, использовавшаяся в русскоязычных версиях операционной системы Windows в начале 90-х годов. Кириллические символы идут в алфавитном порядке. Содержит все символы, встречающиеся в типографике обычного текста (кроме знака ударения).[http://ru.wikipedia.org/wiki/CP1251]&lt;br /&gt;
===Кодировки стандарта UNICODE===&lt;br /&gt;
&lt;br /&gt;
'''Юникод''' или '''Уникод'''  ( англ. Unicode ) - это промышленный стандарт обеспечивающий цифровое представление символов всех письменностей мира, и специальных символов.&lt;br /&gt;
&lt;br /&gt;
Стандарт предложен в 1991 году некоммерческой организацией «Консорциум Юникода» (англ. ''Unicode Consortium, Unicode Inc.'').Применение этого стандарта позволяет закодировать очень большое число символов из разных письменностей.&lt;br /&gt;
Стандарт состоит из двух основных разделов: '''универсальный набор символов''' (англ. ''UCS, universal character set'') и семейство кодировок (англ. ''UTF, Unicode transformation format''). '''Универсальный набор символов''' задаёт однозначное соответствие символов кодам — элементам кодового пространства, представляющим неотрицательные целые числа.Семейство кодировок определяет машинное представление последовательности кодов UCS.&lt;br /&gt;
&lt;br /&gt;
Коды в стандарте Unicode разделены на несколько областей. Область с кодами от U+0000 до U+007F содержит символы набора ASCII с соответствующими кодами. Далее расположены области знаков различных письменностей, знаки пунктуации и технические символы. Под символы кириллицы выделены области знаков с кодами от U+0400 до U+052F, от U+2DE0 до U+2DFF, от U+A640 до U+A69F.&lt;br /&gt;
Часть кодов зарезервирована для использования в будущем.&lt;br /&gt;
&lt;br /&gt;
Юникод имеет несколько форм представления (англ. Unicode Transformation Format, UTF): UTF-8, UTF-16 (UTF-16BE, UTF-16LE) и UTF-32 (UTF-32BE, UTF-32LE). Была разработана также форма представления UTF-7 для передачи по семибитным каналам, но из-за несовместимости с ASCII она не получила распространения и не включена в стандарт.&lt;br /&gt;
 &lt;br /&gt;
====Кодовое пространство====&lt;br /&gt;
Кодовое пространство разбито на 17 плоскостей по 216 (65536) символов. Нулевая плоскость называется базовой, в ней расположены символы наиболее употребительных письменностей. Первая плоскость используется, в основном, для исторических письменностей. Плоскости 15 и 16 выделены для частного употребления.&lt;br /&gt;
&lt;br /&gt;
Для обозначения символов Unicode используется запись вида «U+xxxx» (для кодов 0…FFFF) или «U+xxxxx» (для кодов 10000…FFFFF) или «U+xxxxxx» (для кодов 100000…10FFFF), где xxx — шестнадцатеричные цифры. Например, символ «я» (U+044F) имеет код 044F16 = 110310.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* '''UTF8''' - самая распространенная на данный момент кодировка из семейства UNICODE. [http://ru.wikipedia.org/wiki/UTF-8]&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Unicode||UTF-8||Представленные символы&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x00000000&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;0x0000007F&amp;lt;/code&amp;gt;||&amp;lt;code&amp;gt;0xxxxxxx&amp;lt;/code&amp;gt;||ASCII, в том числе английский алфавит, простейшие знаки препинания и арабские цифры&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x00000080&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;0x000007FF&amp;lt;/code&amp;gt;||&amp;lt;code&amp;gt;110xxxxx 10xxxxxx&amp;lt;/code&amp;gt;||кириллица, расширенная латиница, арабский алфавит, армянский алфавит, греческий алфавит, еврейский алфавит и коптский алфавит; сирийское письмо, тана, нко; Международный фонетический алфавит; некоторые знаки препинания&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x00000800&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;0x0000FFFF&amp;lt;/code&amp;gt;||&amp;lt;code&amp;gt;1110xxxx 10xxxxxx 10xxxxxx&amp;lt;/code&amp;gt;||все другие современные формы письменности, в том числе грузинский алфавит, индийское, китайское, корейское и японское письмо; сложные знаки препинания; математические и другие специальные символы&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x00010000&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;0x001FFFFF&amp;lt;/code&amp;gt;||&amp;lt;code&amp;gt;11110xxx 10xxxxxx 10xxxxxx 10xxxxxx&amp;lt;/code&amp;gt;||музыкальные символы, редкие китайские иероглифы, вымершие формы письменности&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|||&amp;lt;code&amp;gt;111111xx&amp;lt;/code&amp;gt;||служебные символы c, d, e, f&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Также возможны коды длиной в 5 и 6 байт, но на практике они не используются. Это связано с тем, что в стандарт Unicode не входят символы с кодом выше &amp;lt;code&amp;gt;0x10ffff&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====BOM====&lt;br /&gt;
'''Byte Order Mark (BOM)(''метка порядка байтов'')''' - Unicode символ, используемый для индикации порядка байтов текстового файла. Его кодовый символ U+FEFF (ZERO WIDTH NON-BREAKING SPACE)''неразрывный пробел с нулевой шириной'', также именуемый . По спецификации его использование не является обязательным, однако если BOM используется, то он должен быть установлен вначале текстового файла. Помимо своего конкретного использования в качестве указателя порядка байтов, символ может также указать какой кодировкой Unicode закодирован текст.&lt;br /&gt;
[[Файл:Bom.png|thumb|right| 400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+'''Представление BOM в кодировках'''&lt;br /&gt;
|-&lt;br /&gt;
! Кодирование&lt;br /&gt;
! Представление (Шестнадцатеричное)&lt;br /&gt;
|-&lt;br /&gt;
| UTF-8&lt;br /&gt;
| &amp;lt;code&amp;gt;EF BB BF&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| UTF-16 (BE)&lt;br /&gt;
| &amp;lt;code&amp;gt;FE FF&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| UTF-16 (LE)&lt;br /&gt;
| &amp;lt;code&amp;gt;FF FE&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| UTF-32 (BE)&lt;br /&gt;
| &amp;lt;code&amp;gt;00 00 FE FF&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| UTF-32 (LE)&lt;br /&gt;
| &amp;lt;code&amp;gt;FF FE 00 00&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
В кодировке UTF-8, наличие BOM не является существенным, поскольку, нет альтернативной последовательности байтов. Когда BOM используется на страницах или редакторах для контента закодированного в UTF-8, иногда он может представить пробелы или короткие последовательности символов, имеющие странный вид (такие как ï»¿). Именно поэтому, при наличии выбора, для совместимости, как правило, лучше упустить BOM в UTF-8 контенте.Однако BOM могут еще встречаться в тексте закодированном в UTF-8, как побочный продукт перекодирования или потому, что он был добавлен редактором. В этом случае BOM часто называют подписью UTF-8.&lt;br /&gt;
&lt;br /&gt;
Когда символ закодирован в UTF-16, его 2 или 4 байта можно упорядочить двумя разными способами (little-endian или big-endian). Изображение справа показывает это.Byte order mark указывает, какой порядок используется, так что приложения могут немедленно расшифровать контент. UTF-16 контент должен всегда начинатся с BOM.&lt;br /&gt;
&lt;br /&gt;
BOM также используется для текста обозначенного как UTF-32. Аналогично UTF-16 существует два варианта четырёхбайтной кодировки — UTF-32BE и UTF-32LE.К сожалению, этот способ не позволяет надёжно различать UTF-16LE и UTF-32LE, поскольку символ U+0000 допускается Юникодом&lt;br /&gt;
==Примеры==&lt;br /&gt;
Если записать строку 'hello мир' в файл exampleBOM, а затем сделать его hex-дамп, то можно убедиться в том, что разные символы кодируются разным количеством байт. Например, английские буквы,пробел, знаки препинания и пр. кодируются одним байтом, а русские буквы - двумя&lt;br /&gt;
===Код на python===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
#coding:utf-8&lt;br /&gt;
import codecs&lt;br /&gt;
f = open('exampleBOM','w')&lt;br /&gt;
b = u'hello мир'&lt;br /&gt;
f.write(codecs.BOM_UTF8)&lt;br /&gt;
f.write(b.encode('utf-8'))&lt;br /&gt;
f.close()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===hex-дамп файла exampleBOM===&lt;br /&gt;
{|class = &amp;quot;wikitable&amp;quot; border = &amp;quot;1&amp;quot; style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
 |Символ&lt;br /&gt;
 |colspan=&amp;quot;3&amp;quot; |BOM&lt;br /&gt;
 |h||e||l||l||o&lt;br /&gt;
 |Пробел&lt;br /&gt;
 |colspan=&amp;quot;2&amp;quot; |м&lt;br /&gt;
 |colspan=&amp;quot;2&amp;quot; |и&lt;br /&gt;
 |colspan=&amp;quot;2&amp;quot; |р&lt;br /&gt;
 |-&lt;br /&gt;
 |Код в UNICODE&lt;br /&gt;
 |EF&lt;br /&gt;
 |BB&lt;br /&gt;
 |BF&lt;br /&gt;
 |68||65||6C||6C||6F&lt;br /&gt;
 |20||D0||BC||D0||B8||D1||80&lt;br /&gt;
 |-&lt;br /&gt;
 |Код в UTF-8&lt;br /&gt;
 |11101111||10111011||10111111&lt;br /&gt;
 |01101000||01100101||01101100||01101100||01101111&lt;br /&gt;
 |00100000||11010000||10111100||11010000||10111000||11010001||10000000&lt;br /&gt;
 |}&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/ASCII Wikipedia: таблица ASCII]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4 Wikipedia: стандарт UNICODE]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/Byte_order_mark Wikipedia: Byte order mark]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4 Wikipedia: Юникод] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Представление информации]]&lt;/div&gt;</summary>
		<author><name>Freemahn</name></author>	</entry>

	</feed>