
Алгоритм Крускала (или Краскала)
А. построения минимального остовного дерева взвешенного связного неор. графа. Алгоритм впервые описан Джозефом Крускалом (Kruskal)в 1956 году.
Вначале текущее множество рёбер устанавливается пустым. Затем, пока это возможно, проводится след. операция: из всех рёбер, добавление которых к уже имеющемуся множеству не вызовет появление в нём цикла, выбирается ребро минимального веса и добавляется к уже имеющемуся множеству. Когда таких рёбер больше нет, алгоритм завершён. Подграф данного графа, содержащий все его вершины и найденное множество рёбер, является его остовным деревом минимального веса
До начала работы алгоритма необходимо отсортировать рёбра по весу, это требует O(E × log(E)) времени. После чего компоненты связности удобно хранить в виде системы непересекающихся множеств. Эффективность м. принять за O(E * log(E)).
Идея алгоритма. Искомые ребра соединяют вершины. Поэтому возможны две стратегии построения. Можно идти от вершин и для каждой из них искать мин-ное ребро (как это сделано в а. Прима), а м. для каждого ребра выяснять можно ли его включить в строящееся дерево. Алгоритм Крускала предлагает делать это след. образом. Во-первых, ребра графа пронумеровываем в порядке возрастания весов. Затем для каждого ребра начиная с первого проверяем соединяет или нет оно две несвязные вершины, если да, то его можно включить в остовное дерево. Ясно, что если мы имеем V вершин, то работа алгоритма начинается с V несвязных компонент графа (пока из графа все ребра исключаем). Для того, чтобы их связать необходимо найти V-1 ребро.
Др. словами, алгоритм организует процесс роста компонент связности в процессе кот. он объединяются друг с другом до тех пор пока не останется одна являющаяся конечным результатом. Т.е. А. Кр. Строит лес ребер.
Создаем список ребер по возрастанию.
Создаем множество компонент связности каждая из кот. содержит ровно одну вершину.
Пока компонент связности больше чем одна.
Взять ребро из начала списка ребер.
Если ребро соединяет две разных компоненты связности то
Компоненты связности объединить в одну.
Алгоритм Краскала в псевдокоде:
Procedure Kruskal (G,w)
A← 0 //множесво - пусто
Forкаждой в-ныv E|G|
Doсоздать |V| деревьев из одной в-ны
Упорядочить ребра Eпо весам
for (u,v) E (в порядке возрастания веса)
doifконцы ребра не лежат в одном дереве
Then A A (u,v) E|G|
return A
Вначале текущее множество рёбер устанавливается пустым. Затем, пока это возможно, проводится следующая операция: из всех рёбер, добавление которых к уже имеющемуся множеству не вызовет появление в нём цикла, выбирается ребро минимального веса и добавляется к уже имеющемуся множеству. Когда таких рёбер больше нет, алгоритм завершён. Подграф данного графа, содержащий все его вершины и найденное множество рёбер, является его остовным лесом минимального веса.
До начала работы алгоритма необходимо отсортировать рёбра по весу, это требует O(E ? log(E)) времени. После чего компоненты связности удобно хранить в виде системы непересекающихся множеств. Все операции в таком случае займут O(E ? ?(E, V)), где ? — функция, обратная к функции Аккермана. Поскольку для любых практических задач ?(E, V) < 5, то можно принять её за константу, таким образом общее время работы алгоритма Краскала можно принять за O(E).
Задача: на карте расположено несколько населенных пунктов (на плате расположено несколько контактов), необходимо соединить все из них друг с другом таким образом, чтобы суммарная длина дорог (проводов) была минимальной.
* Да, задача в такой формулировке обычно называется «задачей Штейнера» (статья), решив которую, города можно соединить еще дешевле. Но нам-то, в конечном итоге, не асфальт укладывать… =)
Для решения понадобятся:
Графы: Кратко о том, что это такое и как они представляются в коде уже было изложено на Хабре (статья)
Алгоритм Краскала (wiki): основной «движок» для решения задачи в такой формулировке. Он очень хорошо описан в библии Кормена, Лейзерсона «Алгоритмы: построение и анализ» (книга)
Disjoint-set data structure (wiki): дополнительная структура, необходимая для эффективного выполнения вышеупомянутого алгоритма. Как она устроена, описано в той же библии, но только немного под другим названием (если не изменяет память: Union Find-Set, как-то так)
В текущей постановке задачи вершины графа (vi) – представляют собой города, а ребра e(vi, vj) – дороги между городами. Нам известны расстояния между парами городов (vi, vj) – это вес ребер w(e(vi, vj)). Нужно найти MST, т.е. такое дерево в графе (без циклов: зачем строить лишние дороги), чтобы сумма ребер была минимальной и при этом все вершины были достижимы.
Изначально каждая вершина (город) сам по себе и является единственным гордым представителем соответствующего множества G1, G2, … GN (по количеству вершин). Пусть пока думает, что именно она образовала MST. В ходе алгоритма мы эффективно и дипломатично объединим все эти разрозненные множества в одно единственное G так, чтобы участвующие в нем вершины образовали MST. Для этого:
Сортируем все имеющиеся в графе ребра в порядке возрастания длины (дороги)
Пробегая по ребрам в порядке возрастания длин, смотрим на концы ребра e = (a,b):
Если вершины (a и b) принадлежат одному множеству:Значит, они уже участвуют в некотором образованном подмножестве микро-MST, внутри их подграфа сумма ребер уже минимальна. Такое ребро пропускается – оно нам не нужно т.к. иначе оно образует цикл в дереве, и мы зря израсходуем асфальт
Если вершины (a и b) принадлежат разным подмножествам микро-MST:Нужно объединять, т.к. мы нашли ребро (дорогу) минимальной длины, объединяющее (сливающее) оба подмножества в одно. Все ребра меньшей длины уже рассмотрены и дешевле, чем этим ребром, объединить не получится. Такое ребро заносится в список ребер, использованных при построении дерева MST, а множества объединяются в одно
Продолжаем цикл объединения до получения одного единственного множества, равного искомому MST, в котором будут присутствовать все вершины графа
Получаем одно единственное множество вершин (MST) и список ребер, использованных для его объединения, который представляет собой дерево минимальной суммарной длины, объединяющее все вершины.