본문으로 건너뛰기
김신건의 로그

단절점 (Articulation Point)

· 수정 · 📖 약 4분 · 1,300자/단어 #algorithm #graph #articulation-point #dfs
articulation point, 단절점, cut vertex

정의

단절점 (Articulation Point, Cut Vertex) 은 무향 연결 그래프에서 제거했을 때 그래프가 둘 이상의 컴포넌트로 분리되는 정점. Robert Tarjan 의 1972년 논문에서 DFS 기반 O(V+E) 알고리즘이 처음 제시되었다.

문제 상황과 동기

네트워크 신뢰성, 도로망, 서버 클러스터 등에서 하나의 장애로 전체가 분리되는 지점 을 찾는 문제.

  • naive: 정점 하나씩 제거 후 BFS/DFS 로 컴포넌트 개수 확인. O(V · (V+E)). V=10^5 면 불가.
  • Tarjan: DFS 한 번 (O(V+E)) 에 모든 단절점 탐지.

핵심 통찰: DFS 트리 상에서 어떤 정점 u 의 서브트리에서 u 보다 위로 올라가는 back edge 가 없으면 u 는 단절점. disc[u] (발견 시각) 와 low[u] (서브트리에서 도달 가능한 가장 빠른 시각) 두 배열만으로 판정.

시각화

위 애니메이션은 정점 4 를 제거 시 그래프가 두 컴포넌트 {1,2,3} 과 {5,6,7} 로 분리됨을 보여준다.

핵심 아이디어

DFS 트리를 그리며 각 정점 u 에 대해:

  1. disc[u]: DFS 방문 순서 (발견 시각).
  2. low[u]: u 의 서브트리에서 back edge 로 도달 가능한 가장 빠른 disc 값.
low[u] = min(
    disc[u],
    disc[back edge 타겟들],
    low[자식들]
)

단절점 판정

  • root (DFS 시작점): 자식이 2개 이상이면 단절점.
  • non-root u: 어떤 자식 v 에 대해 low[v] >= disc[u] 면 단절점.

왜? v 의 서브트리에서 u 보다 위로 못 올라간다 → u 를 제거하면 v 서브트리 분리.

알고리즘

disc[1..N] = 0, low[1..N] = 0, timer = 0
is_articulation[1..N] = false

dfs(u, parent):
    timer++
    disc[u] = low[u] = timer
    children = 0
    
    for v in adj[u]:
        if disc[v] == 0:
            children++
            dfs(v, u)
            low[u] = min(low[u], low[v])
            
            // non-root 판정
            if parent != -1 and low[v] >= disc[u]:
                is_articulation[u] = true
        else if v != parent:
            // back edge
            low[u] = min(low[u], disc[v])
    
    // root 판정
    if parent == -1 and children >= 2:
        is_articulation[u] = true

for each component root r:
    dfs(r, -1)

구현

// 단절점 탐지, O(V+E)
#include <bits/stdc++.h>
using namespace std;

int V, E, timer = 0;
vector<int> adj[100005];
int disc[100005], low[100005];
bool is_cut[100005];

void dfs(int u, int p) {
  disc[u] = low[u] = ++timer;
  int children = 0;
  for (int v : adj[u]) {
      if (!disc[v]) {
          children++;
          dfs(v, u);
          low[u] = min(low[u], low[v]);
          if (p != -1 && low[v] >= disc[u])
              is_cut[u] = true;
      } else if (v != p) {
          low[u] = min(low[u], disc[v]);
      }
  }
  if (p == -1 && children >= 2)
      is_cut[u] = true;
}

int main() {
  cin >> V >> E;
  for (int i = 0; i < E; i++) {
      int u, v; cin >> u >> v;
      adj[u].push_back(v);
      adj[v].push_back(u);
  }
  for (int i = 1; i <= V; i++) {
      if (!disc[i]) dfs(i, -1);
  }
  vector<int> cuts;
  for (int i = 1; i <= V; i++)
      if (is_cut[i]) cuts.push_back(i);
  cout << cuts.size() << "\n";
  for (int x : cuts) cout << x << " ";
}
stdin
7 8
1 2
1 3
2 3
3 4
4 5
5 6
5 7
6 7
결과
2
3 4

복잡도

항목
시간O(V + E)
공간O(V) (disc, low, recursion stack)
전처리DFS 한 번

변형

단절선 (Bridge)

간선 (u, v) 가 단절선 (bridge, cut edge) ⇔ DFS 트리 상에서 tree edge 이고 low[v] > disc[u].

단절점과 거의 동일 로직, 부등호만 > (등호 제외).

if (low[v] > disc[u]) {
    // (u, v) is a bridge
}

이중 연결 컴포넌트 (Biconnected Component)

단절점을 제거해도 연결된 채로 남는 최대 부분 그래프. DFS 중 스택에 간선을 쌓다가 단절점 발견 시 pop 하여 하나의 BCC 를 구성.

3-edge-connectivity / 3-vertex-connectivity

단절점 2개 이상 제거해야 분리되는 그래프. 선형 시간 알고리즘은 복잡하며, 흔히 network flow 로 접근.

함정

1. root 판정 누락

root 는 자식 2개 이상일 때만 단절점. non-root 판정 로직과 다르다.

if (parent == -1 && children >= 2)
    is_cut[u] = true;

2. 부모 간선을 back edge 로 착각

무향 그래프에서 (u, v)(v, u) 가 모두 인접 리스트에 있다. v == parent 인 경우 back edge 로 처리하면 안 됨.

else if (v != parent) {
    low[u] = min(low[u], disc[v]);
}

3. 다중 컴포넌트 처리 안 함

그래프가 애초에 분리되어 있으면 각 컴포넌트마다 dfs 호출 필요.

for (int i = 1; i <= V; i++)
    if (!disc[i]) dfs(i, -1);

4. disc 와 low 의 의미 혼동

  • disc[u]: u 를 처음 방문한 시각 (변하지 않음).
  • low[u]: u 서브트리에서 back edge 로 도달 가능한 가장 빠른 시각 (갱신됨).

응용

문제 유형설명
네트워크 취약점단절점 = 장애 시 네트워크 분리
도로망 / 전력망도로 하나로만 연결된 섬, 전력 허브
이중 연결 그래프단절점 없는 그래프, 어떤 정점도 제거 가능
단절선 (Bridge)간선 버전, 제거 시 분리되는 간선

BOJ 연습 문제

번호제목정답률링크
BOJ 11266단절점-kokoa-lab
BOJ 11400단절선-kokoa-lab
BOJ 14675단절점과 단절선-kokoa-lab

참고

이 글의 용어 (3개)
강한 연결 요소 (SCC)algorithm
정의 강한 연결 요소 (Strongly Connected Component, SCC) 는 방향 그래프에서 서로 도달 가능한 정점들의 최대 부분 집합. SCC 내 임의 두 정점 u…
깊이 우선 탐색 (DFS)algorithm
정의 깊이 우선 탐색 (Depth-First Search, DFS) 는 그래프 G=(V, E) 에서 갈 수 있는 만큼 깊이 들어가다가 막히면 백트래킹하는 알고리즘. 스택 (LIF…
이중 연결 요소 (BCC, Biconnected Component)algorithm
정의 이중 연결 요소 (Biconnected Component, BCC) 는 무방향 그래프에서 정점 하나를 제거해도 연결성이 유지되는 최대 부분 그래프. 단절점 (articula…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기