← Назад к графовым алгоритмам

Поиск точек сочленения

Нахождение вершин, удаление которых увеличивает число компонент связности

🐍 Python
n, m = map(int, input().split())
G = [[] for _ in range(n)]

for _ in range(m):
    a, b = map(int, input().split())
    a -= 1
    b -= 1
    G[a].append(b)
    G[b].append(a)

used = [0] * n
T = [0] * n      # Время входа
L = [0] * n      # Минимальное достижимое время
A = []           # Точки сочленения
t = 0            # Текущее время

def dfs(h, p):
    global t
    used[h] = 1
    T[h] = t
    L[h] = t
    t += 1
    c = 0
    f = 0
    for a in G[h]:
        if not used[a]:
            c += 1
            dfs(a, h)
            L[h] = min(L[h], L[a])
            if L[a] >= T[h] and p != -1:
                f = 1
        elif a != p:
            L[h] = min(L[h], T[a])
    
    if p == -1 and c >= 2:
        f = 1
    if f:
        A.append(h + 1)

for i in range(n):
    if not used[i]:
        dfs(i, -1)

print(*A)
⚙️ C++
#include <bits/stdc++.h>
using namespace std;

vector<vector<int>> G;
vector<int> used, T, L;
vector<int> articulationPoints;
int t = 0;

void dfs(int h, int p) {
    used[h] = 1;
    T[h] = t;
    L[h] = t;
    t++;
    int c = 0;
    bool f = false;
    
    for (int a : G[h]) {
        if (!used[a]) {
            c++;
            dfs(a, h);
            L[h] = min(L[h], L[a]);
            if (L[a] >= T[h] && p != -1) {
                f = true;
            }
        } else if (a != p) {
            L[h] = min(L[h], T[a]);
        }
    }
    
    if (p == -1 && c >= 2) {
        f = true;
    }
    if (f) {
        articulationPoints.push_back(h + 1);
    }
}

int main() {
    int n, m;
    cin >> n >> m;
    
    G.resize(n);
    used.assign(n, 0);
    T.resize(n);
    L.resize(n);
    
    for (int i = 0; i < m; i++) {
        int a, b;
        cin >> a >> b;
        a--; b--;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    
    for (int i = 0; i < n; i++) {
        if (!used[i]) {
            dfs(i, -1);
        }
    }
    
    for (int v : articulationPoints) {
        cout << v << " ";
    }
    
    return 0;
}

Как работает алгоритм поиска точек сочленения (Тарьяна)?

Точка сочленения — это вершина, удаление которой увеличивает количество компонент связности в графе. Алгоритм Тарьяна находит все точки сочленения за один обход DFS.

Основная идея: вершина h является точкой сочленения, если выполнено одно из условий:

Здесь:

Шаги алгоритма:

Временная сложность: O(n + m), где n — количество вершин, m — количество рёбер.

Пространственная сложность: O(n + m).

Формат ввода и вывода

Ввод:

Вывод:

Пример ввода:

6 7
1 2
1 3
2 3
2 4
4 5
4 6
5 6

Здесь:
n=6, m=7
Граф: треугольник 1-2-3, и компонента 4-5-6, соединённая ребром 2-4

Вывод:
2 4

Вершины 2 и 4 — точки сочленения (удаление 2 оторвёт треугольник от компоненты, удаление 4 оторвёт 5-6 от 4)

Попробовать поиск точек сочленения онлайн

Введите неориентированный граф в формате, описанном выше:

Результат появится здесь...