← Все вопросы

Число компонент связности: считать DFS-ом или через СНМ — и как быстрее на потоке рёбер?

Задан 24 месяца назад1.5к просмотров2 ответа
7

Нужно посчитать число компонент связности неориентированного графа. Делаю DFS из каждой непосещённой вершины и считаю запуски. Но в одной задаче рёбра приходят по одному (онлайн), и пересчитывать DFS каждый раз дорого. Как считать число компонент эффективнее, особенно когда рёбра добавляются?

2 ответа

12
✓ Принятый ответ — помог автору

Статический случай — DFS/BFS. Число запусков обхода из непосещённых вершин = число компонент:

int countComponents(int n, vector<int> g[]) {
    vector<bool> used(n, false); int comp = 0;
    for (int s = 0; s < n; s++) if (!used[s]) {
        comp++;
        // BFS/DFS, помечая всю компоненту used
        queue<int> q; q.push(s); used[s] = true;
        while (!q.empty()) { int v=q.front(); q.pop();
            for (int u: g[v]) if(!used[u]){used[u]=true; q.push(u);} }
    }
    return comp;
}

O(V+E).

Онлайн-добавление рёбер — СНМ. Стартуем с comp = n (каждая вершина — своя компонента). При добавлении ребра (a,b): если unite(a,b) реально слил две разные компоненты — comp--. Так число компонент поддерживается инкрементально за O(α) на ребро:

DSU d(n); int comp = n;
// на каждое новое ребро:
if (d.unite(a, b)) comp--;   // ответ comp всегда актуален

Итого добавить m рёбер и отвечать после каждого — O(m·α(V)), практически линейно. Это куда лучше, чем перезапускать DFS (O(m·(V+E))).

Важно: СНМ умеет только объединять. Если рёбра ещё и удаляются (онлайн disconnect), обычный СНМ не поможет — там нужны оффлайн-приёмы (обработка запросов в обратном порядке, превращающая удаление в добавление) или сложные структуры (link-cut tree / дерево разрезов).

4

Полезный оффлайн-трюк, когда рёбра удаляются: разворачиваем время. Читаем все запросы, оставляем граф без удаляемых рёбер, потом идём по запросам с конца — каждое «удаление» в прямом времени становится «добавлением» в обратном, и снова работает СНМ за O(α). Ответы пишем в обратном порядке. Это классика для «сколько компонент после серии удалений».

И напоминание: для подсчёта компонент сильной связности (ориентированный граф) ни DSU, ни простой DFS-счётчик не годятся — там нужен Тарьян или Косарайю. DSU/обход считают только обычную (слабую/неориентированную) связность.

Ваш ответ

Войдите, чтобы ответить на вопрос.