<?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=A+guy+from+is</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=A+guy+from+is"/>
		<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/A_guy_from_is"/>
		<updated>2026-04-23T06:15:47Z</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%B4%D0%B2%D1%83%D1%85_%D0%BA%D0%B8%D1%82%D0%B0%D0%B9%D1%86%D0%B5%D0%B2&amp;diff=64820</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%B4%D0%B2%D1%83%D1%85_%D0%BA%D0%B8%D1%82%D0%B0%D0%B9%D1%86%D0%B5%D0%B2&amp;diff=64820"/>
				<updated>2018-04-04T23:47:01Z</updated>
		
		<summary type="html">&lt;p&gt;A guy from is: Исправление ошибки в псевдокоде&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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&amp;lt;/tex&amp;gt;. Требуется построить корневое остовное дерево в &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; с корнем в вершине &amp;lt;tex&amp;gt;v&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&amp;lt;/tex&amp;gt; недостижима из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, то требуемое дерево построить нельзя.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|width=&amp;quot;70%&amp;quot;|&lt;br /&gt;
# Для каждой вершины &amp;lt;tex&amp;gt;u \ne v&amp;lt;/tex&amp;gt; графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; произведём следующую операцию: найдём ребро минимального веса, входящее в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;, и вычтем вес этого ребра из весов всех рёбер, входящих в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;m(u) = \min \limits_{tu \in E}w(tu), w'(tu) = w(tu) - m(u)&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
# Строим граф &amp;lt;tex&amp;gt;K = (V,K_0)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;K_0&amp;lt;/tex&amp;gt; — множество рёбер нулевого веса графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; c весовой функцией &amp;lt;tex&amp;gt;w'&amp;lt;/tex&amp;gt;. Если в этом графе найдётся остовное дерево с корнем в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, то оно и будет искомым.&amp;lt;br&amp;gt;&lt;br /&gt;
# Если такого дерева нет, то построим граф &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; — конденсацию графа &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex&amp;gt;y&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;z&amp;lt;/tex&amp;gt; — две вершины графа &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;, отвечающие компонентам сильной связности &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;Z&amp;lt;/tex&amp;gt; графа &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; соответственно. Положим вес ребра между вершинами &amp;lt;tex&amp;gt;y&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;z&amp;lt;/tex&amp;gt; равным минимальному среди весов рёбер графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; с весовой функцией &amp;lt;tex&amp;gt;w'&amp;lt;/tex&amp;gt;, идущих из &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;Z&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
# Продолжим с пункта 2, используя граф &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; вместо &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
# В &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; построено MST &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Построим теперь MST &amp;lt;tex&amp;gt;T'&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; с весовой функцией &amp;lt;tex&amp;gt;w'&amp;lt;/tex&amp;gt;. Добавим к &amp;lt;tex&amp;gt;T'&amp;lt;/tex&amp;gt; все вершины компоненты сильной связности графа &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt;, которой принадлежит &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; (по путям нулевого веса из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;). Пусть в &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; есть ребро &amp;lt;tex&amp;gt;yz&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;y&amp;lt;/tex&amp;gt; отвечает компоненте сильной связности &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;z&amp;lt;/tex&amp;gt; — компоненте сильной связности &amp;lt;tex&amp;gt;Z&amp;lt;/tex&amp;gt; графа &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt;. Между &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;Z&amp;lt;/tex&amp;gt; в графе &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; с весовой функцией &amp;lt;tex&amp;gt;w'&amp;lt;/tex&amp;gt; есть ребро &amp;lt;tex&amp;gt;y'z'&amp;lt;/tex&amp;gt;, вес которого равен весу ребра &amp;lt;tex&amp;gt;yz&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;Z&amp;lt;/tex&amp;gt; по путям нулевого веса из &amp;lt;tex&amp;gt;z'&amp;lt;/tex&amp;gt;. Сделаем так для каждого ребра дерева &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
# Полученное дерево &amp;lt;tex&amp;gt;T'&amp;lt;/tex&amp;gt; — MST в графе &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Пример ===&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot; width=&amp;quot;70%&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Описание !! Изображение &lt;br /&gt;
|-&lt;br /&gt;
|Исходный граф.&lt;br /&gt;
|[[Файл:китайГраф1.png|200px]]&lt;br /&gt;
|-&lt;br /&gt;
|Произведем спуск до нулевых ребер (Фаза 1, 2).&lt;br /&gt;
|[[Файл:китайГраф2.png|200px]]&lt;br /&gt;
|-&lt;br /&gt;
|По нулевым ребрам нельзя дойти до всех вершин из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, поэтому строим конденсацию и добавляем наименьшие ребра между компонентами (Фаза 3).&lt;br /&gt;
Найдем &amp;lt;tex&amp;gt;MST&amp;lt;/tex&amp;gt; для данного графа.&lt;br /&gt;
|[[Файл:китайГраф3.png|200px]]&lt;br /&gt;
|-&lt;br /&gt;
|Произведем спуск до нулевых ребер (Фаза 1, 2).&lt;br /&gt;
|[[Файл:китайГраф4.png|200px]]&lt;br /&gt;
|-&lt;br /&gt;
|По нулевым ребрам нельзя дойти до всех вершин из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, поэтому строим конденсацию и добавляем наименьшие ребра между компонентами (Фаза 3).&lt;br /&gt;
Найдем &amp;lt;tex&amp;gt;MST&amp;lt;/tex&amp;gt; для данного графа.&lt;br /&gt;
|[[Файл:китайГраф5.png|200px]]&lt;br /&gt;
|-&lt;br /&gt;
|Произведем спуск до нулевых ребер (Фаза 1, 2). По полученным нулевым ребрам можно дойти из корня до всех вершин. Тогда запускаем &amp;lt;tex&amp;gt;dfs&amp;lt;/tex&amp;gt; из корня и возвращаем ребра.&lt;br /&gt;
|[[Файл:китайГраф6.png|200px]]&lt;br /&gt;
|-&lt;br /&gt;
|Находим корень в каждой из компонент, из каждого такого корня запускаем &amp;lt;tex&amp;gt;dfs&amp;lt;/tex&amp;gt; по нулевым ребрам, возвращаем результат.&lt;br /&gt;
|[[Файл:китайГраф7.png|200px]]&lt;br /&gt;
|-&lt;br /&gt;
|Находим корень в каждой из компонент, из каждого такого корня запускаем &amp;lt;tex&amp;gt;dfs&amp;lt;/tex&amp;gt; по нулевым ребрам. Полученое дерево и есть &amp;lt;tex&amp;gt;MST&amp;lt;/tex&amp;gt; в исходном графе.&lt;br /&gt;
|[[Файл:китайГраф8.png|200px]]&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; входит по крайней мере одно ребро нулевого веса.&amp;lt;br&amp;gt;&lt;br /&gt;
* Пусть &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; — искомое дерево в &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; с весовой функцией &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;w'(T) = w(T) - \sum \limits_{u \in V \setminus v}m(u)&amp;lt;/tex&amp;gt;, т.е. &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; - MST в &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; с весовой функцией &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; тогда и только тогда, когда &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; — MST в &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; с весовой функцией &amp;lt;tex&amp;gt;w'&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
&lt;br /&gt;
|statement=&lt;br /&gt;
Кратчайшее дерево путей &amp;lt;tex&amp;gt;T'&amp;lt;/tex&amp;gt; в графе &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; можно получить, найдя кратчайшее дерево путей &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; в графе &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;, а затем заменив в нем каждую компоненту сильной связности деревом, построенным из дуг нулевой длинны.&lt;br /&gt;
|proof=&lt;br /&gt;
Зафиксируем любое дерево путей и покажем, что в графе &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; найдется дерево не большей длины, имеющее такую структуру, как сказано в лемме. Для такой структуры дерева необходимо и достаточно, чтобы в каждое из подмножеств входило только по одному ребру. Меньше быть не может, иначе получится отдельная компонента связности. Если же в какое-то подмножество входит больше чем одно ребро, то все ребра кроме одного можно заменить ребрами нулевой длины, лежащими внутри подмножества, что разве лишь уменьшит длину дерева и не нарушит связности. Повторяя это преобразование нужное число раз мы добьемся искомой структуры дерева.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Из сделанных замечаний и леммы следует, что дерево &amp;lt;tex&amp;gt;T'&amp;lt;/tex&amp;gt; — MST в &amp;lt;tex&amp;gt;G&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;
*Ребро - структура {from, to, weight}.&lt;br /&gt;
*root - текущий корень.&lt;br /&gt;
 &lt;br /&gt;
Особенность реализации: алгоритму не важна кратность ребер, поэтому при составлении нового графа кратные ребра могут&lt;br /&gt;
появиться - это уменьшает асимптотику с &amp;lt;tex&amp;gt;O(V^2)&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt; &lt;br /&gt;
 &lt;br /&gt;
 Проверяем, можно ли дойти из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; до остальных вершин. Если можно - запускаем findMST.&lt;br /&gt;
 &lt;br /&gt;
 int findMST(edges, n, root):&lt;br /&gt;
    int res = 0&lt;br /&gt;
    int minEdge[n] // создаем массив минимумов, входящих в каждую компоненту, инициализируем бесконечностью.&lt;br /&gt;
    for each &amp;lt;tex&amp;gt;e \in &amp;lt;/tex&amp;gt; edges&lt;br /&gt;
        minEdge[e.to] = min(e.w, minEdge[e.to])&lt;br /&gt;
    for each &amp;lt;tex&amp;gt;v \in V \backslash \{root\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
        res += minEdge[v] //веса минимальных ребер точно будут в результате&lt;br /&gt;
    edge zeroEdges[] //создаем массив нулевых ребер&lt;br /&gt;
    for each &amp;lt;tex&amp;gt;e \in &amp;lt;/tex&amp;gt; edges&lt;br /&gt;
        if e.w == minEdge[e.to]&lt;br /&gt;
            zeroEdges.pushback(&amp;lt;tex&amp;gt;e_1&amp;lt;/tex&amp;gt;) // &amp;lt;tex&amp;gt;e_1&amp;lt;/tex&amp;gt; - ребро е, уменьшенное на минимальный вес, входящий в e.to&lt;br /&gt;
    if dfs(root, zeroEdges) // проверяем, можно ли дойти до всех вершин по нулевым ребрам&lt;br /&gt;
        return res&lt;br /&gt;
    int newComponents[n] // будущие компоненты связности&lt;br /&gt;
    newComponents = Сondensation(zeroEdges) &lt;br /&gt;
    edge newEdges[] //создаем массив ребер в новом графе с вершинами в полученных компонентах&lt;br /&gt;
    for each &amp;lt;tex&amp;gt;e \in&amp;lt;/tex&amp;gt; edges&lt;br /&gt;
        if e.to и e.from в разных компонентах&lt;br /&gt;
            добавляем в newEdges ребро с концами в данных компонентах и весом e.w - minEdge[e.to]&lt;br /&gt;
    res += findMST(newEdges, ComponentsCount, newComponents[root])&lt;br /&gt;
    return res&lt;br /&gt;
&lt;br /&gt;
=== Сложность ===&lt;br /&gt;
Всего будет построено не более &amp;lt;tex&amp;gt;V&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;
*Романовский И. В. '''Дискретный анализ''', 3-е изд., перераб. и доп. - СПб.:Невский Диалект; БХВ-Петербург, 2003. - 320 с.: ил. - '''ISBN 5-7940-0114-3'''&lt;br /&gt;
* [http://is.ifmo.ru/vis/ctree/ http://is.ifmo.ru]&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Алгоритм Борувки]]&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Edmonds%27_algorithm Edmonds' Algorithm]&lt;br /&gt;
* [http://rain.ifmo.ru/cat/view.php/vis/graph-spanning-trees/shortest-tree-chinese-2003 Визуализатор алгоритма]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Остовные деревья ]]&lt;/div&gt;</summary>
		<author><name>A guy from is</name></author>	</entry>

	</feed>