<?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=93.84.16.25&amp;*</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=93.84.16.25&amp;*"/>
		<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/93.84.16.25"/>
		<updated>2026-08-13T13:01:00Z</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%A4%D0%BE%D1%80%D0%B4%D0%B0-%D0%A4%D0%B0%D0%BB%D0%BA%D0%B5%D1%80%D1%81%D0%BE%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=65181</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%A4%D0%BE%D1%80%D0%B4%D0%B0-%D0%A4%D0%B0%D0%BB%D0%BA%D0%B5%D1%80%D1%81%D0%BE%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=65181"/>
				<updated>2018-05-01T11:59:41Z</updated>
		
		<summary type="html">&lt;p&gt;93.84.16.25: Исправление алгоритма(неправильный символ)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Идея алгоритма==&lt;br /&gt;
Пусть дан [[Основные определения теории графов|неориентированный двудольный граф]] &amp;lt;tex&amp;gt;G(V, E)&amp;lt;/tex&amp;gt; и требуется найти [[Теорема о максимальном паросочетании и дополняющих цепях|максимальное паросочетание]] в нём. Обозначим доли исходного графа как &lt;br /&gt;
&amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;. Построим граф &amp;lt;tex&amp;gt;G'(V', E')&amp;lt;/tex&amp;gt; следующим образом: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;V' = V \cup \{s, t\}&amp;lt;/tex&amp;gt; (т.е. добавим новый исток &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и сток &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;E' = \{(s, u): u \in L\} \cup \{(u, v): u \in L, v \in R\ , (u, v) \in E\} \cup \{(v, t): v \in R\} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
{|align=&amp;quot;center&amp;quot;&lt;br /&gt;
 |-valign=&amp;quot;center&amp;quot;&lt;br /&gt;
 |[[Файл:GrafG.png|thumb|200px|Пример графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.]]&lt;br /&gt;
 |[[Файл:GrafG2.png|thumb|200px|Соответствующий граф &amp;lt;tex&amp;gt;G'&amp;lt;/tex&amp;gt;.]]&lt;br /&gt;
 |}&lt;br /&gt;
Изначально текущее паросочетание пусто. На каждом шаге алгоритма будем поддерживать следующий инвариант: в текущее найденное паросочетание входят те и только те ребра, которые направлены из &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Ищем в графе &amp;lt;tex&amp;gt;G'&amp;lt;/tex&amp;gt; путь из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; [[Обход_в_глубину,_цвета_вершин|поиском в глубину]]. &lt;br /&gt;
# Если путь найден, перезаписываем текущее паросочетание. Далее инвертируем все рёбра на пути (ребро &amp;lt;tex&amp;gt;(u, v)&amp;lt;/tex&amp;gt; становится ребром &amp;lt;tex&amp;gt;(v, u)&amp;lt;/tex&amp;gt; ) и удаляем &amp;lt;tex&amp;gt;(s, L)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;(R, t)&amp;lt;/tex&amp;gt; ребра, покрывающие вершины, принадлежащие текущему паросочетанию.&lt;br /&gt;
# Если путь не был найден, значит текущее паросочетание является максимальным, и алгоритм завершает работу. Иначе переходим к пункту 1.&lt;br /&gt;
&lt;br /&gt;
==Корректность алгоритма==&lt;br /&gt;
&lt;br /&gt;
Обозначим как &amp;lt;tex&amp;gt;p'&amp;lt;/tex&amp;gt; путь &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; без первого и последнего ребра. Пусть он&lt;br /&gt;
является дополняющей цепью для исходного графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;, и пусть также существование дополняющей цепи в графе &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; приводит к существованию пути &amp;lt;tex&amp;gt;p'&amp;lt;/tex&amp;gt;. Тогда из [[Теорема о максимальном паросочетании и дополняющих цепях|теоремы]]: если мы на каком-то шаге можем найти новый путь, т.е  дополняющую цепь, то мы увеличиваем текущее паросочетание. Если путь найти мы уже не можем, значит дополняющих цепей в графе нет и текущее паросочетание — искомое. Осталось доказать что сделанное предположение действительно верно.&lt;br /&gt;
&lt;br /&gt;
Т. к. &amp;lt;tex&amp;gt;p'&amp;lt;/tex&amp;gt; — путь в двудольном графе, начинающийся в &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; и заканчивающийся в &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;, то он нечетной длины. Вершины в нем не повторяются (т.к. это путь в дереве поиска в глубину). Рассмотрим текущее паросочетание. Согласно поддерживаемому инварианту &amp;lt;tex&amp;gt;(R,L)&amp;lt;/tex&amp;gt;-ребра в паросочетании, а  &amp;lt;tex&amp;gt;(L,R)&amp;lt;/tex&amp;gt;-ребра {{---}} нет. В таком случае ребра пути &amp;lt;tex&amp;gt;p'&amp;lt;/tex&amp;gt; можно пронумеровать так, чтобы нечетные ребра были свободными, а четные — покрытыми ребрами текущего паросочетания. Заметим, что путь может начинаться и заканчиваться только в свободной вершине, т. к. из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; ведут ребра только в свободные вершины и только из свободных вершин ведут ребра в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Итак, теперь ясно, что &amp;lt;tex&amp;gt;p'&amp;lt;/tex&amp;gt; — дополняющая цепь для графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обратно, пусть существует дополняющая цепь в графе &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;. В одной из ориентаций она начинается в какой-то свободной вершине &amp;lt;tex&amp;gt;u \in L\&amp;lt;/tex&amp;gt; и заканчивается в свободной вершине &amp;lt;tex&amp;gt;v \in R\&amp;lt;/tex&amp;gt;, далее будем рассматривать именно эту ориентацию. Ребра поочередно то не лежат, то лежат в паросочетании, значит в нашей ориентации эти ребра поочередно ориентированы то &amp;lt;tex&amp;gt;(L, R)&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;(R,L)&amp;lt;/tex&amp;gt;. Заметим что эта ориентация совпадает с ориентацией ребер на пути, а значит в нашем ориентированом графе существует путь из свободной вершины &amp;lt;tex&amp;gt;u \in L&amp;lt;/tex&amp;gt; в свободную вершину &amp;lt;tex&amp;gt;v \in R&amp;lt;/tex&amp;gt;. Нo каждая свободная вершина из &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; связана ребром с &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в графе &amp;lt;tex&amp;gt;G'&amp;lt;/tex&amp;gt;, аналогично каждая свободная вершина из &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt; связана ребром с &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Не сложно заметить, что, в таком случае, &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; достижим из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, а значит в процессе поиска в глубину будет найден некий &amp;lt;tex&amp;gt;s \rightarrow t&amp;lt;/tex&amp;gt; путь &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и соответствующий ему &amp;lt;tex&amp;gt;p'&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;s&amp;lt;/tex&amp;gt; не более чем &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; раз, т.к. из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; ведет ровно &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; ребер, и при каждом запуске одно из них инвертируется. Сам поиск работает за &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, каждая инвертация и перезапись паросочетания так же занимает &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt; времени. Тогда все время алгоритма ограничено &amp;lt;tex&amp;gt;O(VE)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Псевдокод==&lt;br /&gt;
* &amp;lt;tex&amp;gt;px[]&amp;lt;/tex&amp;gt; {{---}} массив вершин &amp;lt;tex&amp;gt;y \in R&amp;lt;/tex&amp;gt;, инцидентные &amp;lt;tex&amp;gt;x_i \in L&amp;lt;/tex&amp;gt; в текущем паросочетании,&lt;br /&gt;
* &amp;lt;tex&amp;gt;py[]&amp;lt;/tex&amp;gt; {{---}} массив вершин &amp;lt;tex&amp;gt;x \in L&amp;lt;/tex&amp;gt;, инцидентные &amp;lt;tex&amp;gt;y_i \in R&amp;lt;/tex&amp;gt; в текущем паросочетании,&lt;br /&gt;
* &amp;lt;tex&amp;gt;vis[]&amp;lt;/tex&amp;gt; {{---}} массив, где помечаются посещенные вершины.&lt;br /&gt;
Максимальное паросочетание {{---}} такие ребра &amp;lt;tex&amp;gt;(x, y)&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;x \in L, y \in R, px[x] = y&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Поиск в глубину, одновременно инвертирующий ребра:&lt;br /&gt;
 '''bool''' dfs(x)''':'''&lt;br /&gt;
     '''if''' vis[x]&lt;br /&gt;
         '''return''' ''false''&lt;br /&gt;
     vis[x] = ''true''&lt;br /&gt;
     '''for''' &amp;lt;tex&amp;gt;(x, y) \in E&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''if''' py[y] == -1&lt;br /&gt;
             py[y] = x&lt;br /&gt;
             px[x] = y&lt;br /&gt;
             '''return''' ''true''&lt;br /&gt;
         '''else'''&lt;br /&gt;
             '''if''' dfs(py[y])&lt;br /&gt;
                 py[y] = x&lt;br /&gt;
                 px[x] = y&lt;br /&gt;
                 '''return''' ''true''&lt;br /&gt;
     '''return''' ''false''&lt;br /&gt;
&lt;br /&gt;
Инициализация и внешний цикл:&lt;br /&gt;
 '''func''' fordFulkerson()''':'''&lt;br /&gt;
     fill(px, -1)&lt;br /&gt;
     fill(py, -1)&lt;br /&gt;
     isPath = ''true''&lt;br /&gt;
     '''while''' isPath&lt;br /&gt;
         isPath = ''false''&lt;br /&gt;
         fill(vis, ''false'')&lt;br /&gt;
         '''for''' &amp;lt;tex&amp;gt;x \in L&amp;lt;/tex&amp;gt;&lt;br /&gt;
             '''if''' px[x] == -1&lt;br /&gt;
                 '''if''' dfs(x)&lt;br /&gt;
                     isPath = ''true''&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях|Теорема о максимальном паросочетании и дополняющих цепях]]&lt;br /&gt;
* [[Алгоритм_Форда-Фалкерсона,_реализация_с_помощью_поиска_в_глубину|Алгоритм Форда-Фалкерсона, реализация с помощью поиска в глубину]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн {{---}} &amp;quot;Алгоритмы: построение и анализ&amp;quot;, 2-е издание, стр. 758 - 761.&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Задача о паросочетании]]&lt;/div&gt;</summary>
		<author><name>93.84.16.25</name></author>	</entry>

	</feed>