<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>https://acm.khpnets.info/w39/index.php?action=history&amp;feed=atom&amp;title=%D0%9C%D0%B8%D0%BD%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%B2%D0%B5%D1%80%D1%88%D0%B8%D0%BD%D0%BD%D0%BE%D0%B5_%D0%BF%D0%BE%D0%BA%D1%80%D1%8B%D1%82%D0%B8%D0%B5%2C_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%BD%D0%B5%D0%B7%D0%B0%D0%B2%D0%B8%D1%81%D0%B8%D0%BC%D0%BE%D0%B5_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%BE</id>
	<title>Минимальное вершинное покрытие, максимальное независимое множество - История изменений</title>
	<link rel="self" type="application/atom+xml" href="https://acm.khpnets.info/w39/index.php?action=history&amp;feed=atom&amp;title=%D0%9C%D0%B8%D0%BD%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%B2%D0%B5%D1%80%D1%88%D0%B8%D0%BD%D0%BD%D0%BE%D0%B5_%D0%BF%D0%BE%D0%BA%D1%80%D1%8B%D1%82%D0%B8%D0%B5%2C_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%BD%D0%B5%D0%B7%D0%B0%D0%B2%D0%B8%D1%81%D0%B8%D0%BC%D0%BE%D0%B5_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%BE"/>
	<link rel="alternate" type="text/html" href="https://acm.khpnets.info/w39/index.php?title=%D0%9C%D0%B8%D0%BD%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%B2%D0%B5%D1%80%D1%88%D0%B8%D0%BD%D0%BD%D0%BE%D0%B5_%D0%BF%D0%BE%D0%BA%D1%80%D1%8B%D1%82%D0%B8%D0%B5,_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%BD%D0%B5%D0%B7%D0%B0%D0%B2%D0%B8%D1%81%D0%B8%D0%BC%D0%BE%D0%B5_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%BE&amp;action=history"/>
	<updated>2026-05-13T11:45:15Z</updated>
	<subtitle>История изменений этой страницы в вики</subtitle>
	<generator>MediaWiki 1.39.3</generator>
	<entry>
		<id>https://acm.khpnets.info/w39/index.php?title=%D0%9C%D0%B8%D0%BD%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%B2%D0%B5%D1%80%D1%88%D0%B8%D0%BD%D0%BD%D0%BE%D0%B5_%D0%BF%D0%BE%D0%BA%D1%80%D1%8B%D1%82%D0%B8%D0%B5,_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%BD%D0%B5%D0%B7%D0%B0%D0%B2%D0%B8%D1%81%D0%B8%D0%BC%D0%BE%D0%B5_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%BE&amp;diff=2715&amp;oldid=prev</id>
		<title>Ctrlalt: Новая страница: «Минимальное вершинное покрытие (minimum vertex cover, MVC) — минимальный по размеру набор вершин, с...»</title>
		<link rel="alternate" type="text/html" href="https://acm.khpnets.info/w39/index.php?title=%D0%9C%D0%B8%D0%BD%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%B2%D0%B5%D1%80%D1%88%D0%B8%D0%BD%D0%BD%D0%BE%D0%B5_%D0%BF%D0%BE%D0%BA%D1%80%D1%8B%D1%82%D0%B8%D0%B5,_%D0%BC%D0%B0%D0%BA%D1%81%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%BD%D0%B5%D0%B7%D0%B0%D0%B2%D0%B8%D1%81%D0%B8%D0%BC%D0%BE%D0%B5_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%BE&amp;diff=2715&amp;oldid=prev"/>
		<updated>2021-08-31T01:33:25Z</updated>

		<summary type="html">&lt;p&gt;Новая страница: «Минимальное вершинное покрытие (minimum vertex cover, MVC) — минимальный по размеру набор вершин, с...»&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая страница&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Минимальное вершинное покрытие (minimum vertex cover, MVC) — минимальный по размеру набор вершин, содержащий хотя бы один конец каждого ребра.&lt;br /&gt;
&lt;br /&gt;
В двудольном графе размер минимального вершинного покрытия совпадает с размером максимального паросочетания.&lt;br /&gt;
&lt;br /&gt;
Максимальное независимое множество (maximum independent set, MIS) — максимальный по размеру набор вершин, никакие две из которых не соединены ребром.&lt;br /&gt;
&lt;br /&gt;
В любом графе максимальное независимое множество — дополнение минимального вершинного покрытия (содержит все вершины, не входящие в минимальное вершинное покрытие).&lt;br /&gt;
&lt;br /&gt;
== Построение ==&lt;br /&gt;
&lt;br /&gt;
{|width=100%&lt;br /&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;
:* Рёбра из максимального паросочетания ориентируем из правой доли в левую&lt;br /&gt;
:* Рёбра не из максимального паросочетания ориентируем из левой доли в правую&lt;br /&gt;
* Запускаем DFS из всех вершин левой доли вспомогательного графа, в которые не входят рёбра&lt;br /&gt;
* MVC — объединение {{Changed|непосещённых}} вершин левой доли и {{Changed|посещённых}} вершин правой доли&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|&lt;br /&gt;
* Вычисляем максимальное паросочетание&lt;br /&gt;
* Строим вспомогательный ориентированный двудольный граф&lt;br /&gt;
:* Рёбра из максимального паросочетания ориентируем из правой доли в левую&lt;br /&gt;
:* Рёбра не из максимального паросочетания ориентируем из левой доли в правую&lt;br /&gt;
* Запускаем DFS из всех вершин левой доли вспомогательного графа, в которые не входят рёбра&lt;br /&gt;
* MIS — объединение {{Changed|посещённых}} вершин левой доли и {{Changed|непосещённых}} вершин правой доли&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
 struct Data {&lt;br /&gt;
     int an = 0, bn = 0;&lt;br /&gt;
     vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; edges;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 Data readData() {&lt;br /&gt;
     Data d;&lt;br /&gt;
     int edgeCount;&lt;br /&gt;
 &lt;br /&gt;
     cin &amp;gt;&amp;gt; d.an &amp;gt;&amp;gt; d.bn &amp;gt;&amp;gt; edgeCount;&lt;br /&gt;
 &lt;br /&gt;
     d.edges.resize(edgeCount);&lt;br /&gt;
     for (auto &amp;amp;[a, b] : d.edges)&lt;br /&gt;
         cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;&lt;br /&gt;
 &lt;br /&gt;
     return d;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Graph computeMaxMatching(Data &amp;amp;d) {&lt;br /&gt;
     Graph g(1 + d.an + d.bn + 1);&lt;br /&gt;
 &lt;br /&gt;
     for (int a = 0; a &amp;lt; d.an; a++)&lt;br /&gt;
         g.addEdge(0, 1 + a, 1);&lt;br /&gt;
 &lt;br /&gt;
     for (auto &amp;amp;[a, b] : d.edges)&lt;br /&gt;
         g.addEdge(1 + a, 1 + d.an + b, 1);&lt;br /&gt;
 &lt;br /&gt;
     for (int b = 0; b &amp;lt; d.bn; b++)&lt;br /&gt;
         g.addEdge(1 + d.an + b, 1 + d.an + d.bn, 1);&lt;br /&gt;
 &lt;br /&gt;
     g.maxFlow(0, 1 + d.an + d.bn);&lt;br /&gt;
 &lt;br /&gt;
     return g;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; buildMVCGraph(Data &amp;amp;d, Graph &amp;amp;g) {&lt;br /&gt;
     vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mg(d.an + d.bn);&lt;br /&gt;
 &lt;br /&gt;
     for (auto &amp;amp;[a, b, _, flow] : g.edges) {&lt;br /&gt;
         if (0 != a &amp;amp;&amp;amp; b != 1 + d.an + d.bn) {&lt;br /&gt;
             if (flow)&lt;br /&gt;
                 mg[b - 1].push_back(a - 1);&lt;br /&gt;
             else&lt;br /&gt;
                 mg[a - 1].push_back(b - 1);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     return mg;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void dfs(vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; &amp;amp;g, int v, vector&amp;lt;int&amp;gt; &amp;amp;visited) {&lt;br /&gt;
     visited[v] = 1;&lt;br /&gt;
     for (int to : g[v])&lt;br /&gt;
         if (!visited[to])&lt;br /&gt;
             dfs(g, to, visited);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 pair&amp;lt;vector&amp;lt;int&amp;gt;, vector&amp;lt;int&amp;gt;&amp;gt; computeMVC(Data &amp;amp;d, vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; &amp;amp;g) {&lt;br /&gt;
     set&amp;lt;int&amp;gt; startVertices;&lt;br /&gt;
     for (int i = 0; i &amp;lt; d.an; i++)&lt;br /&gt;
         startVertices.insert(i);&lt;br /&gt;
 &lt;br /&gt;
     for (auto &amp;amp;row : g)&lt;br /&gt;
         for (int to : row)&lt;br /&gt;
             startVertices.erase(to);&lt;br /&gt;
 &lt;br /&gt;
     vector&amp;lt;int&amp;gt; visited(d.an + d.bn);&lt;br /&gt;
     for (int v : startVertices)&lt;br /&gt;
         dfs(g, v, visited);&lt;br /&gt;
 &lt;br /&gt;
     vector&amp;lt;int&amp;gt; a;&lt;br /&gt;
     for (int i = 0; i &amp;lt; d.an; i++)&lt;br /&gt;
         if ({{Changed|!visited[i]}})&lt;br /&gt;
             a.push_back(i);&lt;br /&gt;
 &lt;br /&gt;
     vector&amp;lt;int&amp;gt; b;&lt;br /&gt;
     for (int i = 0; i &amp;lt; d.bn; i++)&lt;br /&gt;
         if ({{Changed|visited[d.an + i]}})&lt;br /&gt;
             b.push_back(i);&lt;br /&gt;
 &lt;br /&gt;
     return { a, b };&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void solve() {&lt;br /&gt;
     auto d = readData();&lt;br /&gt;
     auto g = computeMaxMatching(d);&lt;br /&gt;
     auto mg = buildMVCGraph(d, g);&lt;br /&gt;
     auto [a, b] = computeMVC(d, mg);&lt;br /&gt;
 }&lt;br /&gt;
|&lt;br /&gt;
 struct Data {&lt;br /&gt;
     int an = 0, bn = 0;&lt;br /&gt;
     vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; edges;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 Data readData() {&lt;br /&gt;
     Data d;&lt;br /&gt;
     int edgeCount;&lt;br /&gt;
 &lt;br /&gt;
     cin &amp;gt;&amp;gt; d.an &amp;gt;&amp;gt; d.bn &amp;gt;&amp;gt; edgeCount;&lt;br /&gt;
 &lt;br /&gt;
     d.edges.resize(edgeCount);&lt;br /&gt;
     for (auto &amp;amp;[a, b] : d.edges)&lt;br /&gt;
         cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;&lt;br /&gt;
 &lt;br /&gt;
     return d;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Graph computeMaxMatching(Data &amp;amp;d) {&lt;br /&gt;
     Graph g(1 + d.an + d.bn + 1);&lt;br /&gt;
 &lt;br /&gt;
     for (int a = 0; a &amp;lt; d.an; a++)&lt;br /&gt;
         g.addEdge(0, 1 + a, 1);&lt;br /&gt;
 &lt;br /&gt;
     for (auto &amp;amp;[a, b] : d.edges)&lt;br /&gt;
         g.addEdge(1 + a, 1 + d.an + b, 1);&lt;br /&gt;
 &lt;br /&gt;
     for (int b = 0; b &amp;lt; d.bn; b++)&lt;br /&gt;
         g.addEdge(1 + d.an + b, 1 + d.an + d.bn, 1);&lt;br /&gt;
 &lt;br /&gt;
     g.maxFlow(0, 1 + d.an + d.bn);&lt;br /&gt;
 &lt;br /&gt;
     return g;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; buildMVCGraph(Data &amp;amp;d, Graph &amp;amp;g) {&lt;br /&gt;
     vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; mg(d.an + d.bn);&lt;br /&gt;
 &lt;br /&gt;
     for (auto &amp;amp;[a, b, _, flow] : g.edges) {&lt;br /&gt;
         if (0 != a &amp;amp;&amp;amp; b != 1 + d.an + d.bn) {&lt;br /&gt;
             if (flow)&lt;br /&gt;
                 mg[b - 1].push_back(a - 1);&lt;br /&gt;
             else&lt;br /&gt;
                 mg[a - 1].push_back(b - 1);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     return mg;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void dfs(vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; &amp;amp;g, int v, vector&amp;lt;int&amp;gt; &amp;amp;visited) {&lt;br /&gt;
     visited[v] = 1;&lt;br /&gt;
     for (int to : g[v])&lt;br /&gt;
         if (!visited[to])&lt;br /&gt;
             dfs(g, to, visited);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 pair&amp;lt;vector&amp;lt;int&amp;gt;, vector&amp;lt;int&amp;gt;&amp;gt; computeMIS(Data &amp;amp;d, vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; &amp;amp;g) {&lt;br /&gt;
     set&amp;lt;int&amp;gt; startVertices;&lt;br /&gt;
     for (int i = 0; i &amp;lt; d.an; i++)&lt;br /&gt;
         startVertices.insert(i);&lt;br /&gt;
 &lt;br /&gt;
     for (auto &amp;amp;row : g)&lt;br /&gt;
         for (int to : row)&lt;br /&gt;
             startVertices.erase(to);&lt;br /&gt;
 &lt;br /&gt;
     vector&amp;lt;int&amp;gt; visited(d.an + d.bn);&lt;br /&gt;
     for (int v : startVertices)&lt;br /&gt;
         dfs(g, v, visited);&lt;br /&gt;
 &lt;br /&gt;
     vector&amp;lt;int&amp;gt; a;&lt;br /&gt;
     for (int i = 0; i &amp;lt; d.an; i++)&lt;br /&gt;
         if ({{Changed|visited[i]}})&lt;br /&gt;
             a.push_back(i);&lt;br /&gt;
 &lt;br /&gt;
     vector&amp;lt;int&amp;gt; b;&lt;br /&gt;
     for (int i = 0; i &amp;lt; d.bn; i++)&lt;br /&gt;
         if ({{Changed|!visited[d.an + i]}})&lt;br /&gt;
             b.push_back(i);&lt;br /&gt;
 &lt;br /&gt;
     return { a, b };&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 void solve() {&lt;br /&gt;
     auto d = readData();&lt;br /&gt;
     auto g = computeMaxMatching(d);&lt;br /&gt;
     auto mg = buildMVCGraph(d, g);&lt;br /&gt;
     auto [a, b] = computeMIS(d, mg);&lt;br /&gt;
 }&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
Теория:&lt;br /&gt;
* [https://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%B2%D1%8F%D0%B7%D1%8C_%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_%D0%B8_%D0%BC%D0%B8%D0%BD%D0%B8%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE_%D0%B2%D0%B5%D1%80%D1%88%D0%B8%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%BE%D0%BA%D1%80%D1%8B%D1%82%D0%B8%D1%8F_%D0%B2_%D0%B4%D0%B2%D1%83%D0%B4%D0%BE%D0%BB%D1%8C%D0%BD%D1%8B%D1%85_%D0%B3%D1%80%D0%B0%D1%84%D0%B0%D1%85 neerc.ifmo.ru/wiki — Связь максимального паросочетания и минимального вершинного покрытия в двудольных графах]&lt;br /&gt;
* [https://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%B2%D1%8F%D0%B7%D1%8C_%D0%B2%D0%B5%D1%80%D1%88%D0%B8%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BF%D0%BE%D0%BA%D1%80%D1%8B%D1%82%D0%B8%D1%8F_%D0%B8_%D0%BD%D0%B5%D0%B7%D0%B0%D0%B2%D0%B8%D1%81%D0%B8%D0%BC%D0%BE%D0%B3%D0%BE_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%B0 neerc.ifmo.ru/wiki — Связь вершинного покрытия и независимого множества]&lt;/div&gt;</summary>
		<author><name>Ctrlalt</name></author>
	</entry>
</feed>