Открыть сервис

Алгоритм Краскала

Алгоритм Краскала — это жадный алгоритм в теории графов, предназначенный для нахождения минимального остовного дерева (МОД) во взвешенном неориентированном связном графе. Алгоритм последовательно добавляет рёбра в порядке возрастания их весов, избегая образования циклов, что гарантирует построение остова с минимальной суммарной массой. Назван в честь американского математика Джозефа Краскала, впервые опубликовавшего алгоритм в 1956 году.

История

Алгоритм был предложен Джозефом Краскалом (Joseph Kruskal, 1928–2010) в статье «On the Shortest Spanning Subtree of a Graph and the Traveling Salesman Problem», опубликованной в журнале Proceedings of the American Mathematical Society в 1956 году. Работа Краскала стала одним из первых систематических методов решения задачи о минимальном остовном дереве, которая до этого решалась эвристически. Примерно в то же время чешский математик Войтех Ярник (1929) и голландский учёный Эдсгер Дейкстра (1959) предложили альтернативный алгоритм Прима, решающий ту же задачу, но иным способом. Алгоритм Краскала остаётся одним из фундаментальных алгоритмов дискретной математики и широко применяется в компьютерных науках, проектировании сетей и кластерном анализе.

Постановка задачи

Дано: связный неориентированный граф \( G = (V, E) \), где \( V \) — множество вершин, \( E \) — множество рёбер, каждому ребру \( e \in E \) приписан положительный вес \( w(e) \). Требуется найти остовное дерево \( T \subseteq E \), соединяющее все вершины \( V \), такое, что сумма весов рёбер \( \sum_{e \in T} w(e) \) минимальна. Остовное дерево — это подграф, не содержащий циклов и содержащий ровно \( |V| - 1 \) ребро.

Описание алгоритма

Алгоритм Краскала работает по следующей схеме:

  1. Сортировка рёбер. Все рёбра графа сортируются в порядке неубывания весов.
  2. Инициализация. Создаётся пустое множество рёбер будущего остовного дерева \( T \). Каждая вершина графа помещается в отдельное подмножество (компоненту связности).
  3. Последовательный просмотр. Для каждого ребра в отсортированном списке (от наименьшего веса к наибольшему) проверяется, соединяет ли оно две вершины из разных компонент связности. Если да, то ребро добавляется в \( T \), и компоненты объединяются. Если нет (ребро образует цикл), оно отбрасывается.
  4. Завершение. Алгоритм останавливается, когда в \( T \) набрано \( |V| - 1 \) ребро, или когда все рёбра просмотрены.

Пример работы

Рассмотрим граф с вершинами A, B, C, D и рёбрами: AB (1), AC (3), AD (4), BC (2), BD (5), CD (6). Сортировка рёбер по весу: AB (1), BC (2), AC (3), AD (4), BD (5), CD (6).

  • Добавляем AB (1). Компоненты: {A,B}, {C}, {D}.
  • Добавляем BC (2). Соединяет {A,B} и {C} → {A,B,C}, {D}.
  • Рассматриваем AC (3). Обе вершины в одной компоненте {A,B,C} — отбрасываем.
  • Добавляем AD (4). Соединяет {A,B,C} и {D} → {A,B,C,D}. Получено 3 ребра (|V|-1=3). Остовное дерево: AB, BC, AD. Суммарный вес: 1+2+4=7.

Реализация

Для эффективной реализации алгоритма Краскала требуется структура данных для поддержания непересекающихся множеств (Disjoint Set Union, DSU), которая позволяет быстро выполнять две операции:

  • Find — определение, какой компоненте принадлежит вершина.
  • Unionобъединение двух компонент.

Псевдокод на языке, близком к Python:

```python def kruskal(vertices, edges):

edges: список кортежей (вес, u, v)

edges.sort(key=lambda x: x[0]) # сортировка по весу parent = {v: v for v in vertices} rank = {v: 0 for v in vertices}

def find(v): while parent[v] != v: parent[v] = parent[parent[v]] v = parent[v] return v

def union(u, v): ru, rv = find(u), find(v) if ru == rv: return False if rank[ru] < rank[rv]: parent[ru] = rv elif rank[ru] > rank[rv]: parent[rv] = ru else: parent[rv] = ru rank[ru] += 1 return True

mst = [] total_weight = 0 for weight, u, v in edges: if union(u, v): mst.append((u, v, weight)) total_weight += weight if len(mst) == len(vertices) - 1: break return mst, total_weight ```

Анализ сложности

  • Временная сложность: \( O(E \log E) \) или \( O(E \log V) \), где \( E \) — количество рёбер, \( V \) — количество вершин. Основное время тратится на сортировку рёбер. Операции DSU (с эвристиками сжатия пути и объединения по рангу) выполняются почти за константное время (обратная функция Аккермана).
  • Пространственная сложность: \( O(V + E) \) для хранения графа и структур данных.

Доказательство корректности

Корректность алгоритма Краскала основывается на свойстве разреза графа и лемме о безопасном ребре. Пусть на каждом шаге алгоритма \( T \) — множество уже выбранных рёбер. Рассмотрим очередное ребро \( e \) минимального веса, соединяющее две разные компоненты связности. Существует разрез, разделяющий эти компоненты, и \( e \) — ребро минимального веса через этот разрез. Следовательно, \( e \) является безопасным для \( T \), и его добавление не нарушает возможность построения минимального остовного дерева. Алгоритм завершается, когда получено \( |V|-1 \) ребро, что гарантирует связность и ацикличность.

Варианты и модификации

  • Обратный алгоритм Краскала (reverse-delete algorithm): начинается с полного графа и удаляет рёбра в порядке убывания веса, если это не нарушает связность. Менее эффективен, но полезен для некоторых задач.
  • Алгоритм Борувки (1926) — исторически первый алгоритм для МОД, работающий за \( O(E \log V) \). Используется в параллельных вычислениях.
  • Алгоритм Прима — альтернативный жадный алгоритм, строящий дерево от одной вершины, также за \( O(E \log V) \) с использованием очереди с приоритетами.

Применение

Интересные факты

  • Алгоритм Краскала является одним из первых примеров жадного алгоритма, для которого было строго доказано, что он даёт глобально оптимальное решение.
  • В 1957 году, через год после публикации Краскала, Роберт Прим независимо опубликовал свой алгоритм, который позже был усовершенствован Эдсгером Дейкстрой.
  • Алгоритм Краскала может быть легко адаптирован для работы с графами, содержащими рёбра отрицательного веса, при условии отсутствия циклов отрицательного веса.
  • В параллельных вычислениях существуют версии алгоритма Краскала, использующие сортировку слиянием и параллельные DSU, что позволяет ускорить обработку больших графов.

Источники

  • Kruskal, J. B. (1956). "On the shortest spanning subtree of a graph and the traveling salesman problem". Proceedings of the American Mathematical Society, 7(1), 48–50.
  • Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2009). Introduction to Algorithms (3rd ed.). MIT Press. Глава 23.
  • Sedgewick, R., & Wayne, K. (2011). Algorithms (4th ed.). Addison-Wesley.
  • Ахо, А., Хопкрофт, Дж., Ульман, Дж. (2000). Структуры данных и алгоритмы. Вильямс.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →