Алгоритм Борувки — различия между версиями
Novik (обсуждение | вклад) м (→Доказательство корректности) |
Novik (обсуждение | вклад) |
||
Строка 1: | Строка 1: | ||
− | <b>Алгоритм Борувки</b> (англ. ''Borůvka's algorithm'') {{---}} алгоритм поиска минимального остовного дерева | + | <b>Алгоритм Борувки</b> (англ. ''Borůvka's algorithm'') {{---}} алгоритм поиска [[Остовные деревья: определения, лемма о безопасном ребре | минимального остовного дерева]] во взвешенном неориентированном связном графе. |
Впервые был опубликован в 1926 году Отакаром Борувкой. | Впервые был опубликован в 1926 году Отакаром Борувкой. | ||
==Описание алгоритма== | ==Описание алгоритма== | ||
− | # Изначально | + | # Изначально каждая вершина графа <tex> G </tex >{{---}} тривиальное дерево, а ребра не принадлежат никакому дереву. |
− | # Для каждого дерева <tex> T </tex> найдем минимальное инцидентное ему ребро. | + | # Для каждого дерева <tex> T </tex> найдем минимальное инцидентное ему ребро. Добавим все такие ребра. |
# Повторяем шаг <tex> 2 </tex> пока в графе не останется только одно дерево <tex> T </tex>. | # Повторяем шаг <tex> 2 </tex> пока в графе не останется только одно дерево <tex> T </tex>. | ||
− | Данный алгоритм может работать неправильно, если в графе есть ребра равные по весу. Например, полный граф из трех вершин, вес каждого ребра равен один. В <tex>T</tex> могут быть добавлены все три ребра. Избежать эту проблему можно, выбирая в первом пункте среди ребер, равных по весу, ребро с наименьшим номером. | + | Данный алгоритм может работать неправильно, если в графе есть ребра равные по весу. Например, полный граф из трех вершин, вес каждого ребра равен один. В <tex>T</tex> могут быть добавлены все три ребра. Избежать эту проблему можно, например, выбирая в первом пункте среди ребер, равных по весу, ребро с наименьшим номером. |
==Доказательство корректности== | ==Доказательство корректности== | ||
Строка 24: | Строка 24: | ||
==Реализация== | ==Реализация== | ||
− | У вершины есть поле comp {{---}} компонента связности, которой принадлежит эта вершина. | + | У вершины есть поле <tex>\mathtt{comp}</tex> {{---}} компонента связности, которой принадлежит эта вершина. |
{| width = 100% | {| width = 100% | ||
Строка 33: | Строка 33: | ||
'''function''' <tex>\mathtt{boruvkaMST}():</tex> | '''function''' <tex>\mathtt{boruvkaMST}():</tex> | ||
'''while''' <tex>T\mathtt{.size} < n - 1</tex> | '''while''' <tex>T\mathtt{.size} < n - 1</tex> | ||
− | '''for''' <tex>k \in </tex> Component | + | '''for''' <tex>k \in </tex> Component <font color = "green">// Component — множество компонент связности в <tex>T</tex></font> |
− | <tex>w(\mathtt{minEdge}[k])=\infty</tex> // для каждой компоненты связности вес минимального ребра = <tex>\infty</tex> | + | <tex>w(\mathtt{minEdge}[k])=\infty</tex> <font color = "green">// для каждой компоненты связности вес минимального ребра = <tex>\infty</tex></font> |
− | <tex>\mathtt{findComp(}T\mathtt{)}</tex> | + | <tex>\mathtt{findComp(}T\mathtt{)}</tex> <font color = "green">// разбиваем граф <tex>T</tex> на компоненты связности обычным ''dfs''-ом</font> |
'''for''' <tex>\mathtt{(u,v)} \in E </tex> | '''for''' <tex>\mathtt{(u,v)} \in E </tex> | ||
'''if''' <tex>\mathtt{u.comp} \neq \mathtt{v.comp}</tex> | '''if''' <tex>\mathtt{u.comp} \neq \mathtt{v.comp}</tex> | ||
Строка 43: | Строка 43: | ||
<tex>\mathtt{minEdge}[\mathtt{v.comp}] = (u,v)</tex> | <tex>\mathtt{minEdge}[\mathtt{v.comp}] = (u,v)</tex> | ||
'''for''' <tex>k \in </tex> Component | '''for''' <tex>k \in </tex> Component | ||
− | <tex>T\mathtt{.addEdge}(\mathtt{minEdge}[k])</tex> | + | <tex>T\mathtt{.addEdge}(\mathtt{minEdge}[k])</tex> <font color = "green">// добавляем ребро если его не было в <tex>T</tex></font> |
'''return''' <tex>T</tex> | '''return''' <tex>T</tex> | ||
|} | |} | ||
Строка 52: | Строка 52: | ||
|- | |- | ||
|[[Файл:Boruvka_1.png|250px]] | |[[Файл:Boruvka_1.png|250px]] | ||
− | | {A}<br/>{B}<br/>{C}<br/>{D}<br/>{E}<br/>{F}<br/>{G} | + | | <tex>{A}</tex><br/><tex>{B}</tex><br/><tex>{C}</tex><br/><tex>{D}</tex><br/><tex>{E}</tex><br/><tex>{F}</tex><br/><tex>{G}</tex> |
|Начальный граф <tex>G</tex>. Каждая вершина является компонентой (синие окружности). | |Начальный граф <tex>G</tex>. Каждая вершина является компонентой (синие окружности). | ||
|- | |- | ||
|[[Файл:Boruvka_2.png|250px]] | |[[Файл:Boruvka_2.png|250px]] | ||
− | | {ABDF}<br/>{CEG} | + | | <tex>{ABDF}</tex><br/><tex>{CEG}</tex> |
|На первой итерации внешнего цикла для каждой компоненты были добавлены минимальные сопряженные ребра. Некоторые ребра добавлены несколько раз (<tex dpi = 120>AD</tex> и <tex dpi = 120>CE</tex>). Осталось две компоненты. | |На первой итерации внешнего цикла для каждой компоненты были добавлены минимальные сопряженные ребра. Некоторые ребра добавлены несколько раз (<tex dpi = 120>AD</tex> и <tex dpi = 120>CE</tex>). Осталось две компоненты. | ||
|- | |- | ||
|[[Файл:Boruvka_3.png|250px]] | |[[Файл:Boruvka_3.png|250px]] | ||
− | | {ABCDEFG} | + | | <tex>{ABCDEFG}</tex> |
|На последней итерации внешнего цикла было добавлено минимальное ребро, соединяющее две оставшиеся компоненты (ребро <tex dpi = 120>BE</tex>). Осталась одна компонента. Минимальное остовное дерево графа <tex dpi = 120>G</tex> построено. | |На последней итерации внешнего цикла было добавлено минимальное ребро, соединяющее две оставшиеся компоненты (ребро <tex dpi = 120>BE</tex>). Осталась одна компонента. Минимальное остовное дерево графа <tex dpi = 120>G</tex> построено. | ||
|- | |- | ||
Строка 66: | Строка 66: | ||
==Асимптотика== | ==Асимптотика== | ||
− | Внешний цикл повторяется <tex>\log{V}</tex> раз, так как количество компонент связности каждый раз уменьшается в двое и изначально равно количеству вершин. Что же касается внутреннего цикла, то он выполняется за <tex>E</tex>, где <tex>E</tex> {{---}} количество рёбер в исходном графе. Следовательно конечное время работы алгоритма <tex>O(E\log{V})</tex>. | + | Внешний цикл повторяется <tex>\log{V}</tex> раз, так как количество компонент связности каждый раз уменьшается как минимум в двое(потому что в худшем случае будут объединятся пары компонент) и изначально равно количеству вершин. Что же касается внутреннего цикла, то он выполняется за <tex>E</tex>, где <tex>E</tex> {{---}} количество рёбер в исходном графе. Следовательно конечное время работы алгоритма <tex>O(E\log{V})</tex>. |
==См. также== | ==См. также== |
Версия 18:41, 11 октября 2015
Алгоритм Борувки (англ. Borůvka's algorithm) — алгоритм поиска минимального остовного дерева во взвешенном неориентированном связном графе. Впервые был опубликован в 1926 году Отакаром Борувкой.
Содержание
Описание алгоритма
- Изначально каждая вершина графа — тривиальное дерево, а ребра не принадлежат никакому дереву.
- Для каждого дерева найдем минимальное инцидентное ему ребро. Добавим все такие ребра.
- Повторяем шаг пока в графе не останется только одно дерево .
Данный алгоритм может работать неправильно, если в графе есть ребра равные по весу. Например, полный граф из трех вершин, вес каждого ребра равен один. В могут быть добавлены все три ребра. Избежать эту проблему можно, например, выбирая в первом пункте среди ребер, равных по весу, ребро с наименьшим номером.
Доказательство корректности
Теорема: |
Алгоритм Борувки строит MST |
Доказательство: |
Очевидно, что в результате работы алгоритма получается дерево. Пусть — минимальное остовное дерево графа , а — дерево полученное после работы алгоритма.Покажем, что .Предположим обратное Понятно, что в момент, когда ребро . Пусть ребро — первое окрашенное ребро дерева , не принадлежащее дереву . Пусть — путь, соединяющий в дереве вершины ребра . красили, какое-то ребро (назовем его ) не было покрашено. По алгоритму . Однако тогда — остовное дерево веса не превышающего вес дерева . Получили противоречение. Следовательно . |
Реализация
У вершины есть поле
— компонента связности, которой принадлежит эта вершина.
//— исходный граф // — весовая функция function while for Component // Component — множество компонент связности в // для каждой компоненты связности вес минимального ребра = // разбиваем граф на компоненты связности обычным dfs-ом for if if if for Component // добавляем ребро если его не было в return |
Пример
Асимптотика
Внешний цикл повторяется
раз, так как количество компонент связности каждый раз уменьшается как минимум в двое(потому что в худшем случае будут объединятся пары компонент) и изначально равно количеству вершин. Что же касается внутреннего цикла, то он выполняется за , где — количество рёбер в исходном графе. Следовательно конечное время работы алгоритма .