Алгоритм Борувки — различия между версиями
Alex z (обсуждение | вклад) |
AlexeyL (обсуждение | вклад) |
||
Строка 1: | Строка 1: | ||
− | <b>Алгоритм Борувки</b> — алгоритм поиска минимального остовного дерева (minimum spanning tree, MST) во взвешенном неориентированном связном графе. | + | <b>Алгоритм Борувки</b> (англ. ''Borůvka's algorithm'') — алгоритм поиска минимального остовного дерева (англ. ''minimum spanning tree, MST'') во взвешенном неориентированном связном графе. |
Впервые был опубликован в 1926 году Отакаром Борувкой. | Впервые был опубликован в 1926 году Отакаром Борувкой. | ||
==Описание алгоритма== | ==Описание алгоритма== | ||
− | + | # Построим граф <tex>T</tex>. Изначально <tex>T</tex> содержит все вершины из <tex>G</tex> и не содержит ребер (каждая вершина в графе <tex>T</tex> {{---}} отдельная компонента связности). | |
− | + | # Будем добавлять в <tex>T</tex> ребра следующим образом, пока <tex>T</tex> не является деревом | |
− | Будем добавлять в <tex>T</tex> ребра следующим образом | + | #* Для каждой компоненты связности находим минимальное по весу ребро, которое связывает эту компоненту с другой. |
− | + | #* Добавим в <tex>T</tex> все найденные рёбра. | |
− | + | # Получившийся граф <tex>T</tex> является минимальным остовным деревом графа <tex>G</tex>. | |
− | # Для каждой компоненты связности находим минимальное по весу ребро, которое связывает | ||
− | # Добавим в <tex>T</tex> все | ||
− | |||
− | Получившийся граф <tex>T</tex> является минимальным остовным деревом графа <tex>G</tex>. | ||
Данный алгоритм может работать неправильно, если в графе есть ребра равные по весу. Например, полный граф из трех вершин, вес каждого ребра равен один. В <tex>T</tex> могут быть добавлены все три ребра. Избежать эту проблему можно, выбирая в первом пункте среди ребер, равных по весу, ребро с наименьшим номером. | Данный алгоритм может работать неправильно, если в графе есть ребра равные по весу. Например, полный граф из трех вершин, вес каждого ребра равен один. В <tex>T</tex> могут быть добавлены все три ребра. Избежать эту проблему можно, выбирая в первом пункте среди ребер, равных по весу, ребро с наименьшим номером. | ||
Строка 21: | Строка 17: | ||
|id=lemma1 | |id=lemma1 | ||
|statement=Рассмотрим связный неориентированный взвешенный граф <tex> G = (V, E) </tex> с инъективной весовой функцией <tex>w : E \to \mathbb{R}</tex> . | |statement=Рассмотрим связный неориентированный взвешенный граф <tex> G = (V, E) </tex> с инъективной весовой функцией <tex>w : E \to \mathbb{R}</tex> . | ||
− | Тогда после первой итерации главного цикла алгоритма Борувки получившийся подграф можно достроить до MST. | + | Тогда после первой итерации главного цикла алгоритма Борувки получившийся подграф можно достроить до ''MST''. |
− | |proof=Предположим обратное: пусть любое MST графа <tex>G</tex> не содержит <tex>T</tex>. Рассмотрим какое-нибудь MST. Тогда существует ребро <tex>x</tex> из <tex>T</tex> такое что <tex>x</tex> не принадлежит MST. Добавив ребро <tex>x</tex> в MST, получаем цикл в котором <tex>x</tex> не максимально, т.к оно было минимальным. Тогда, исходя из [[Критерий Тарьяна минимальности остовного дерева|критерия Тарьяна]], получаем противоречие. | + | |proof=Предположим обратное: пусть любое ''MST'' графа <tex>G</tex> не содержит <tex>T</tex>. Рассмотрим какое-нибудь ''MST''. Тогда существует ребро <tex>x</tex> из <tex>T</tex> такое что <tex>x</tex> не принадлежит ''MST''. Добавив ребро <tex>x</tex> в ''MST'', получаем цикл в котором <tex>x</tex> не максимально, т.к оно было минимальным. Тогда, исходя из [[Критерий Тарьяна минимальности остовного дерева|критерия Тарьяна]], получаем противоречие. |
}} | }} | ||
Строка 28: | Строка 24: | ||
{{Теорема | {{Теорема | ||
|id=th1. | |id=th1. | ||
− | |statement=Алгоритм Борувки строит MST. | + | |statement=Алгоритм Борувки строит ''MST''. |
− | |proof=Очевидно, что алгоритм Борувки строит дерево.Будем доказывать что после каждой итерации главного цикла в алгоритме Борувки текущий подграф <tex>T</tex> можно достроить до MST. | + | |proof=Очевидно, что алгоритм Борувки строит дерево.Будем доказывать что после каждой итерации главного цикла в алгоритме Борувки текущий подграф <tex>T</tex> можно достроить до ''MST''. |
Докажем это по индукции. | Докажем это по индукции. | ||
− | + | '''База. ''' <tex>n = 1</tex>([[#lemma1|Лемма]]). | |
− | + | ||
− | Получаем <tex>T'</tex> можно достроить до MST. Следовательно предположение индукции верно. | + | '''Переход. ''' Пусть лес <tex>T</tex>, получившийся после <tex>n</tex> итераций алгоритма, можно достроить до ''MST''. Докажем, что после <tex>n+1</tex> итерации получившийся лес <tex>T'</tex> можно достроить до ''MST''. Предположим обратное: <tex>T'</tex> нельзя достроить до ''MST''. Тогда существует <tex>F</tex> = ''MST'' графа <tex>G</tex>, содержащее <tex>T</tex> и не содержащее <tex>T'</tex>. Тогда рассмотрим цикл, получающийся добавлением в <tex>F</tex> какого-нибудь ребра <tex>x</tex> из <tex>T' {{---}} T</tex>. На этом цикле имеется ребро, большее по весу чем ребро <tex>x</tex>, иначе компонента для которой <tex>x</tex> является минимальным ребром ни с кем больше ни связана. Исходя из [[Критерий Тарьяна минимальности остовного дерева|критерия Тарьяна]], получаем противоречие. |
+ | |||
+ | '''Получаем. ''' <tex>T'</tex> можно достроить до ''MST''. Следовательно предположение индукции верно. | ||
}} | }} | ||
Строка 45: | Строка 43: | ||
|- | |- | ||
| | | | ||
− | + | <font color=green>// <tex>G</tex> {{---}} исходный граф</font> | |
− | while T.size < n - 1 | + | <font color=green>// <tex>w</tex> {{---}} весовая функция</font> |
− | + | '''function''' <tex>\mathtt{boruvkaMST}():</tex> | |
− | findComp(T) | + | '''while''' <tex>T\mathtt{.size} < n - 1</tex> |
− | for | + | '''for''' <tex>k \in </tex> Component // Component — множество компонент связности в <tex>T</tex> |
− | if u.comp | + | <tex>w(\mathtt{minEdge}[k])=\infty</tex> // для каждой компоненты связности вес минимального ребра = <tex>\infty</tex> |
− | if minEdge[u.comp] | + | <tex>\mathtt{findComp(}T\mathtt{)}</tex> // разбиваем граф <tex>T</tex> на компоненты связности обычным ''dfs''-ом |
− | minEdge[u.comp] = | + | '''for''' <tex>\mathtt{(u,v)} \in E </tex> |
− | if minEdge[v.comp] | + | '''if''' <tex>\mathtt{u.comp} \neq \mathtt{v.comp}</tex> |
− | minEdge[v.comp] = | + | '''if''' <tex>w(\mathtt{minEdge}[\mathtt{u.comp}]) < w(u,v)</tex> |
− | for | + | <tex>\mathtt{minEdge}[\mathtt{u.comp}] = (u,v)</tex> |
− | + | '''if''' <tex>w(\mathtt{minEdge}[\mathtt{v.comp}]) < w(u,v)</tex> | |
− | return T | + | <tex>\mathtt{minEdge}[\mathtt{v.comp}] = (u,v)</tex> |
+ | '''for''' <tex>k \in </tex> Component | ||
+ | <tex>T\mathtt{.addEdge}(\mathtt{minEdge}[k])</tex> // добавляем ребро если его не было в <tex>T</tex> | ||
+ | '''return''' <tex>T</tex> | ||
|} | |} | ||
==Пример== | ==Пример== | ||
{| class = "wikitable" | {| class = "wikitable" | ||
− | ! Изображение !! | + | ! Изображение !! Компоненты связности !! Описание |
|- | |- | ||
− | |[[Файл: | + | |[[Файл:Step_0.png|200px]] |
| | | | ||
− | | | + | |Начальный граф <tex>T</tex> |
− | |||
− | |||
|- | |- | ||
− | | | + | |[[Файл:Step_1.png|200px]] |
− | | | + | | <center>'''a''' '''b''' '''c''' '''d''' '''e'''</center> |
+ | |Распределим вершины по компонентам. | ||
|- | |- | ||
− | |[[Файл: | + | |[[Файл:1step_2.png|200px]] |
− | | | + | | <center>'''a''' '''b''' '''c''' '''d''' '''e'''</center> |
− | + | |Пометим минимальные пути между компонентами. | |
− | |||
− | |||
|- | |- | ||
− | |[[Файл: | + | |[[Файл:1step_3.png|200px]]<br/> |
− | |<center>''' | + | |<center>'''bae''' '''cd'''</center> |
− | | | + | |Объединим соединившиеся компоненты в одну и добавим минимальные рёбра к графу <tex>T</tex><br/> |
|- | |- | ||
− | | | + | |[[Файл:1step_4.png|200px]] |
− | |<center>''' | + | |<center>'''bae''' '''cd'''</center> |
− | | | + | |Пометим минимальные пути между компонентами. |
|- | |- | ||
− | |[[Файл: | + | |[[Файл:1step_5.png|200px]] |
− | | | + | |<center>'''baecd'''</center> |
− | | | + | |Объединим соединившиеся компоненты в одну и добавим минимальные рёбра к графу <tex>T</tex><br/> |
|} | |} | ||
==Асимптотика== | ==Асимптотика== | ||
− | + | Внешний цикл повторяется <tex>\log{V}</tex> раз, так как количество компонент связности каждый раз уменьшается в двое и изначально равно количеству вершин. Что же касается внутреннего цикла, то он выполняется за <tex>E</tex>, где <tex>E</tex> {{---}} количество рёбер в исходном графе. Следовательно конечное время работы алгоритма <tex>O(E\log{V})</tex>. | |
− | |||
− | |||
− | |||
− | |||
==См. также== | ==См. также== | ||
Строка 107: | Строка 101: | ||
* [http://rain.ifmo.ru/cat/view.php/vis/graph-spanning-trees/mst-2006 Визуализатор алгоритма] | * [http://rain.ifmo.ru/cat/view.php/vis/graph-spanning-trees/mst-2006 Визуализатор алгоритма] | ||
* [http://www.csee.wvu.edu/~ksmani/courses/fa01/random/lecnotes/lecture11.pdf Minimum Spanning Trees] | * [http://www.csee.wvu.edu/~ksmani/courses/fa01/random/lecnotes/lecture11.pdf Minimum Spanning Trees] | ||
− | * [ | + | * [[wikipedia:ru:Алгоритм Борувки|Алгоритм Борувки— Википедия]] |
[[Категория: Алгоритмы и структуры данных]] | [[Категория: Алгоритмы и структуры данных]] | ||
[[Категория: Остовные деревья ]] | [[Категория: Остовные деревья ]] |
Версия 18:05, 3 декабря 2014
Алгоритм Борувки (англ. Borůvka's algorithm) — алгоритм поиска минимального остовного дерева (англ. minimum spanning tree, MST) во взвешенном неориентированном связном графе. Впервые был опубликован в 1926 году Отакаром Борувкой.
Содержание
Описание алгоритма
- Построим граф . Изначально содержит все вершины из и не содержит ребер (каждая вершина в графе — отдельная компонента связности).
- Будем добавлять в
- Для каждой компоненты связности находим минимальное по весу ребро, которое связывает эту компоненту с другой.
- Добавим в все найденные рёбра.
ребра следующим образом, пока не является деревом
- Получившийся граф является минимальным остовным деревом графа .
Данный алгоритм может работать неправильно, если в графе есть ребра равные по весу. Например, полный граф из трех вершин, вес каждого ребра равен один. В
могут быть добавлены все три ребра. Избежать эту проблему можно, выбирая в первом пункте среди ребер, равных по весу, ребро с наименьшим номером.Доказательство будем проводить, считая веса всех ребер различными.
Доказательство корректности
Лемма: |
Рассмотрим связный неориентированный взвешенный граф с инъективной весовой функцией .
Тогда после первой итерации главного цикла алгоритма Борувки получившийся подграф можно достроить до MST. |
Доказательство: |
Предположим обратное: пусть любое MST графа критерия Тарьяна, получаем противоречие. | не содержит . Рассмотрим какое-нибудь MST. Тогда существует ребро из такое что не принадлежит MST. Добавив ребро в MST, получаем цикл в котором не максимально, т.к оно было минимальным. Тогда, исходя из
Теорема: |
Алгоритм Борувки строит MST. |
Доказательство: |
Очевидно, что алгоритм Борувки строит дерево.Будем доказывать что после каждой итерации главного цикла в алгоритме Борувки текущий подграф можно достроить до MST.Докажем это по индукции. База. Лемма). (Переход. Пусть лес критерия Тарьяна, получаем противоречие. Получаем. , получившийся после итераций алгоритма, можно достроить до MST. Докажем, что после итерации получившийся лес можно достроить до MST. Предположим обратное: нельзя достроить до MST. Тогда существует = MST графа , содержащее и не содержащее . Тогда рассмотрим цикл, получающийся добавлением в какого-нибудь ребра из . На этом цикле имеется ребро, большее по весу чем ребро , иначе компонента для которой является минимальным ребром ни с кем больше ни связана. Исходя из можно достроить до MST. Следовательно предположение индукции верно. |
Реализация
У вершины есть поле comp — компонента связности, которой принадлежит эта вершина.
//— исходный граф // — весовая функция function while for Component // Component — множество компонент связности в // для каждой компоненты связности вес минимального ребра = // разбиваем граф на компоненты связности обычным dfs-ом for if if if for Component // добавляем ребро если его не было в return |
Пример
Асимптотика
Внешний цикл повторяется
раз, так как количество компонент связности каждый раз уменьшается в двое и изначально равно количеству вершин. Что же касается внутреннего цикла, то он выполняется за , где — количество рёбер в исходном графе. Следовательно конечное время работы алгоритма .