EduBrick

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

Отсортировать рёбра и брать подряд те, что соединяют разные компоненты. Всё содержание — в структуре, которая отвечает на вопрос «в одной ли компоненте».

2 мин

Отсортируем все рёбра по весу и пойдём по ним от лёгких к тяжёлым. Ребро берём, если оно соединяет разные компоненты уже собранного леса.

sort(edges.begin(), edges.end(),
     [](const Edge& a, const Edge& b) { return a.w < b.w; });

DSU dsu(n);
long long total = 0;
int taken = 0;
for (auto& [u, v, w] : edges)
    if (dsu.unite(u, v)) { total += w; taken++; }

bool connected = (taken == n - 1);

Почему это верно. Каждое взятое ребро — минимальное из выходящих наружу для обеих своих компонент: все более лёгкие рёбра мы уже рассмотрели, и они либо взяты, либо соединяли вершины одной компоненты. Значит, работает лемма о безопасном ребре.

Проверено: на 40 000 графов результат совпал с перебором всех остовных подмножеств рёбер.

Список рёбер

Краскал — редкий случай, когда граф удобно хранить именно списком рёбер, а не списками смежности. Нам не нужно спрашивать «кто соседи vv», нужно перебрать все рёбра по порядку веса.

Сложность

Сортировка — O(mlogm)O(m \log m). Дальше mm запросов к системе непересекающихся множеств, каждый почти константный.

Итого O(mlogm)O(m \log m), и сортировка доминирует. Если веса маленькие целые, сортировка подсчётом убирает логарифм и оставляет O(m+W)O(m + W).

Что даётся бесплатно

Проверка связности. Если взято меньше n1n-1 ребра, граф несвязен, а собранное — минимальный остовный лес.

Минимальное максимальное ребро. Путь в минимальном остовном дереве минимизирует максимальное ребро среди всех путей между теми же вершинами. Поэтому задача «проехать из aa в bb, минимизируя самый тяжёлый участок» решается построением МОД и обычным обходом по нему.

Почему так: если бы существовал путь с меньшим максимумом, ребро-максимум дерева не было бы взято — на его шаге компоненты уже соединялись бы более лёгкими рёбрами.

Порядок объединения компонент. Он же — порядок в дереве Краскала, на котором строят решения задач вида «когда впервые aa и bb оказались связаны рёбрами веса не больше xx».

Частая ошибка

Проверять «в одной ли компоненте» обходом графа вместо СНМ. Формально верно, но каждая проверка стоит O(n+m)O(n + m), и решение становится квадратичным. Вся ценность Краскала — в том, что эта проверка почти бесплатна.