Опубликован: 05.01.2015 | Доступ: свободный | Студентов: 2177 / 0 | Длительность: 63:16:00
Лекция 20:

Минимальные остовные деревья

Алгоритм Борувки

Следующий алгоритм вычисления MST, который мы рассмотрим, также является самым старым. Подобно алгоритму Крускала, мы строим MST, добавляя ребра в расширяющийся лес MST-поддеревьев, но делаем это поэтапно, добавляя в MST по нескольку ребер. На каждом этапе мы отыскиваем наиболее короткое ребро, которое соединяет каждое MST-поддерево с каким-то другим, а затем включаем все такие ребра в MST.

И опять разработанный в "Введение" АТД объединения-поиска позволяет получить эффективную реализацию. Для рассматриваемой задачи лучше расширить интерфейс этого АТД, чтобы операция найти была доступна в клиентских программах. Мы будем пользоваться этой функцией для присваивания индекса каждому поддереву, чтобы можно было быстро определить, к какому поддереву принадлежит заданная вершина. Это позволит нам эффективно реализовать все операции, необходимые для работы алгоритма Борувки.

Вначале мы строим вектор, индексированный именами вершин, который для каждого MST-поддерева определяет ближайшего соседа. Затем для каждого ребра графа мы выполняем следующие операции:

  • Если оно соединяет две вершины одного и того же дерева, отбрасываем его.
  • Иначе проверяем расстояния между вершинами деревьев, которые соединяет это ребро и при необходимости изменяем их.

После просмотра всех ребер графа вектор ближайших соседних вершин содержит информацию, которая нужна для соединения поддеревьев. Для каждого индекса вершины мы выполняем операцию объединить, чтобы соединить ее с ближайшей соседней вершиной. На следующем этапе мы отбрасываем все более длинные ребра, которые соединяют другие пары вершин в уже соединенных MST-поддеревьях. Работа нашего алгоритма продемонстрирована на рис. 20.14 и 20.15.

Программа 20.9 представляет собой непосредственную реализацию алгоритма Борувки. Ее эффективность обусловлена тремя следующими главными факторами:

  • Трудоемкость каждой операции найти фактически постоянна.
  • Каждый этап уменьшает количество MST-поддеревьев в лесе по крайней мере в два раза.
  • На каждом этапе отбрасывается значительное количество ребер.
 Алгоритм Борувки вычисления MST

Рис. 20.14. Алгоритм Борувки вычисления MST

На верхней диаграмме показаны ориентированные ребра, проведенные из каждой вершины к ближайшему соседу. Из этой диаграммы следует, что ребра 0-2, 1-7 и 3-5 являются самыми короткими ребрами, инцидентными обеим их вершинам, 6-7 — кратчайшее ребро для вершины 6, а 4-3 — кратчайшее ребро для вершины 4. Все эти ребра принадлежат MST и образуют лес MST-поддеревьев (в центре), вычисляемый на первом этапе выполнения алгоритма Борувки. На втором этапе алгоритм завершает вычисление MST-поддеревьев (внизу). Для этого добавляет-сяребро 0-7 — кратчайшее ребро, инцидентное каждой вершине тех поддеревьев, которые оно соединяет; и ребра 4-7 — кратчайшее ребро, инцидентное каждой вершине нижнего поддерева.

 Массив объединения-поиска в алгоритме Борувки

Рис. 20.15. Массив объединения-поиска в алгоритме Борувки

Здесь показано содержимое массива объединения-поиска, соответствующего примеру с рис. 20.14. Первоначально каждый элемент содержит свой собственный индекс, что означает лес изолированных вершин. После выполнения первого этапа мы получаем три компонента, представленные вершинами 0, 1 и 3 (для такого маленького примера все деревья объединения-поиска являются плоскими). По окончании второго этапа остается единственный компонент, представленный вершиной 1.

Программа 20.9. Алгоритм Борувки вычисления MST

Эта реализация алгоритма Борувки вычисления MST использует версию АТД объединения-поиска из "Абстрактные типы данных" (в интерфейс добавлена функция find с одним аргументом), которая связывает индексы с MST-поддеревьями по мере их построения. На каждом этапе проверяются все оставшиеся ребра, и те, которые соединяют отдельные поддеревья, сохраняются до следующего этапа. Массив a содержит еще не отброшенные ребра, которые пока не включены в MST-поддеревья. Индекс N используется для хранения ребер, отложенных до следующего этапа (в конце каждого этапа в E заносится значение N), а индекс h используется для доступа к следующему проверяемому ребру. Ближайший сосед каждого компонента хранится в массиве b с find номерами компонентов в качестве индексов. В конце каждого этапа каждый компонент соединяется с ближайшим соседним, а ребра ближайшей соседней вершины добавляются в дерево MST.

  template <class Graph, class Edge>
  class MST
    { const Graph &G;
      vector<Edge *> a, b, mst;
      UF uf;
    public:
      MST(const Graph &G): G(G), uf(G.V()), mst(G.V()+1)
        { a = edges<Graph, Edge>(G);
          int N, k = 1;
          for (int E = a.size(); E != 0; E = N)
            { int h, i, j;
              b.assign(G.V(), 0);
              for (h = 0, N = 0; h < E; h++)
                { Edge *e = a[h];
                  i = uf.find(e->v()), j = uf.find(e->w());
                  if (i == j) continue;
                  if (!b[i] || e->wt() < b[i]->wt()) b[i] = e;
                  if (!b[j] || e->wt() < b[j]->wt()) b[j] = e;
                  a[N++] = e;
                }
              for (h = 0; h < G.V(); h++)
                if (b[h])
                  if (!uf.find(i = b[h]->v(), j = b[h]->w()))
                    { uf.unite(i, j); mst[k++] = b[h]; }
             }
        }
    };
      

Все эти факторы трудно оценить точно, однако нетрудно установить следующую границу.

Лемма 20.11. Время вычисления MSTзаданного графа алгоритмом Борувки равно $O(E lgV lg^{\bullet }E)$.

Доказательство. Поскольку на каждом этапе количество деревьев в лесе уменьшается по крайней мере наполовину, количество этапов не превышает значения lgV. Время выполнения каждого этапа не более чем пропорционально трудоемкости E операций найти, что меньше E lg*E, то есть практически линейно. $\blacksquare$

Оценка времени, приведенная в лемме 20.11, представляет собой осторожную верхнюю границу, поскольку в ней не учитывается существенное уменьшение количества ребер на каждом этапе. На ранних этапах операция найти выполняется за постоянное время, а на последних этапах остается совсем немного ребер. Для многих графов количество ребер экспоненциально убывает в зависимости от количества вершин, а общее время выполнения пропорционально E. Например, как показано на рис. 20.16, рассматриваемый алгоритм находит MST нашего большого демонстрационного графа всего за четыре этапа.

 Алгоритм Борувки вычисления MST

Рис. 20.16. Алгоритм Борувки вычисления MST

Для построения MST в данном примере достаточно всего четырех этапов (сверху вниз).

Множитель $lg^{\bullet }E$ можно устранить, и тогда теоретическая граница времени выполнения алгоритма Борувки еще уменьшится и станет пропорциональна E lgV. Для этого вместо использования операций объединить и найти необходимо представить MST-поддеревья в виде двухсвязных списков. Однако это усовершенствование гораздо сложнее для реализации, а возможное повышение производительности не настолько заметно, чтобы стоило применять его на практике (см. упражнения 20.66 и 20.67).

Как было сказано, алгоритм Борувки — самый старый алгоритм из рассматриваемых нами: его идея впервые была выдвинута в 1926 г. для управления распределением электроэнергии. Затем он был заново открыт Сойеном (Sollin) в 1961 г.; а позже он привлек к себе внимание как основа для алгоритмов вычисления MST с эффективной асимптотической производительностью и как основа для алгоритмов параллельного построения MST.

Упражнения

20.61. Покажите в стиле рис. 20.14 результат вычисления алгоритмом Борувки MST для сети, определенной в упражнении 20.26.

20.62. Почему программа 20.9 выполняет проверку операции найти перед выполнением операции объединить? Указание. Рассмотрите ребра одинаковой длины.

20.63. Объясните, почему в программе 20.9 в проверке, защищающей операцию найти, значение b(h) может быть пустым.

20.64. Опишите семейство графов с Vвершинами и E ребрами, для которых количество ребер, которые остаются после каждого этапа алгоритма Борувки, достаточно велико для того, чтобы время выполнения было равно времени для худшего случая.

20.65. Разработайте реализацию алгоритма Борувки, основанную на предварительной сортировке ребер.

20.66. Разработайте реализацию алгоритма Борувки, который использует для представления MST-поддеревьев двухсвязные кольцевые списки, чтобы на каждом этапе можно было выполнять слияние и переименование поддеревьев за время, пропорциональное E (тогда АТД отношения эквивалентности не нужен).

20.67. Эмпирически сравните реализацию алгоритма Борувки из упражнения 20.66 с реализацией, приведенной в тексте (программа 20.9) для различных взвешенных графов (см. упражнения 20.9—20.14).

20.68. Составьте на основе эмпирических данных таблицу с количеством этапов и количеством ребер, обрабатываемых на каждом этапе в алгоритме Борувки для различных взвешенных графов (см. упражнения 20.9—20.14).

20.69. Разработайте реализацию алгоритма Борувки, которая на каждом этапе строит новый граф (по одной вершине для каждого дерева в лесе).

20.70. Напишите клиентскую программу, которая выполняет динамическую графическую анимацию алгоритма Борувки (см. упражнения 20.52 и 20.60). Проверьте полученную программу на случайных евклидовых графах с соседними связями и на решетчатых графах (см. упражнения 20.17 и 20.19) , используя столько точек, сколько можно обработать за приемлемое время.

Бактыгуль Асаинова
Бактыгуль Асаинова

Здравствуйте прошла курсы на тему Алгоритмы С++. Но не пришел сертификат и не доступен.Где и как можно его скаачат?

Александра Боброва
Александра Боброва

Я прошла все лекции на 100%.

Но в https://www.intuit.ru/intuituser/study/diplomas ничего нет.

Что делать? Как получить сертификат?