PS❯BOJ2021-10-313 min read
[BOJ 11266] 단절점 - Java (DFS Spanning Tree & Tarjan 알고리즘)
무향 연결 그래프에서 특정 정점을 제거했을 때 그래프가 둘 이상으로 나뉘는지 DFS 방문 순서와 역방향 간선 도달 가능성을 비교하여 판별하는 단절점 알고리즘
#BOJ#단절점#그래프#DFS#Tarjan#Java
1. 문제 개요 및 조건 분석
| 항목 | 내용 |
|---|---|
| 문제 이름 | 단절점 (백준 11266번 / 플래티넘 4) |
| 플랫폼 / 난이도 | 백준 (플래티넘 4, 11266번) |
| 문제 링크 | 백준 11266번 |
| 제한 사항 | 시간 제한 2초, 메모리 제한 128MB |
| 입력 조건 | 정점 수 $V \le 10,000$, 간선 수 $E \le 100,000$ (무향 그래프, 여러 개의 연결 컴포넌트 가능) |
| 핵심 규칙 | 어떤 정점을 제거했을 때 그래프가 2개 이상으로 분리되는 **모든 단절점(Articulation Point)**을 오름차순 출력 |
2. 접근 아이디어: DFS Spanning Tree & Tarjan 단절점 판별법
단절점(Articulation Point / Cut Vertex) 판별 2대 원칙
무향 그래프에서 DFS를 수행하여 형성되는 DFS 스패닝 트리에서 특정 정점 $u$가 단절점인지 여부는 다음 두 조건으로 완벽히 판별됩니다:
- 루트 노드인 경우:
- DFS 탐색의 시작점이 되는 루트 노드는 자식 서브트리의 개수가 2개 이상이면 단절점입니다. (스패닝 트리 상에서 루트가 끊어지면 두 자식 서브트리는 서로 연결될 경로가 없음)
- 루트가 아닌 일반 노드인 경우:
- 정점 $u$의 어떤 자식 $v$에 대해, $v$와 그 서브트리 노드들이 역방향 간선(Back edge)을 타고 올라갈 수 있는 가장 높은 조상의 방문 순서 $low[v]$가 $$low[v] \ge order[u]$$ 를 만족한다면, $v$의 서브트리는 $u$를 거치지 않고는 $u$의 부모나 그 조상으로 갈 수 없으므로 $u$는 단절점입니다.
3. Java 풀이 코드
import java.io.*;
import java.util.*;
public class Main {
static int v, e;
static List<Integer>[] adj;
static int[] order;
static boolean[] isCutPoint;
static int timer = 1;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
v = Integer.parseInt(st.nextToken());
e = Integer.parseInt(st.nextToken());
adj = new ArrayList[v + 1];
for (int i = 1; i <= v; i++) adj[i] = new ArrayList<>();
for (int i = 0; i < e; i++) {
st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
adj[a].add(b);
adj[b].add(a);
}
order = new int[v + 1];
isCutPoint = new boolean[v + 1];
// 분리된 그래프가 있을 수 있으므로 모든 정점 확인
for (int i = 1; i <= v; i++) {
if (order[i] == 0) {
dfs(i, true);
}
}
int count = 0;
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= v; i++) {
if (isCutPoint[i]) {
count++;
sb.append(i).append(" ");
}
}
System.out.println(count);
if (count > 0) {
System.out.println(sb.toString().trim());
}
}
static int dfs(int u, boolean isRoot) {
order[u] = timer++;
int low = order[u];
int childCount = 0;
for (int next : adj[u]) {
if (order[next] > 0) {
// 이미 방문한 노드 (역방향 간선)
low = Math.min(low, order[next]);
} else {
childCount++;
int childLow = dfs(next, false);
// 비루트 노드 단절점 조건
if (!isRoot && childLow >= order[u]) {
isCutPoint[u] = true;
}
low = Math.min(low, childLow);
}
}
// 루트 노드 단절점 조건
if (isRoot && childCount >= 2) {
isCutPoint[u] = true;
}
return low;
}
}
4. 복잡도 분석
- 시간 복잡도: $O(V + E)$ — DFS 1회 순회로 모든 정점과 간선을 상수 횟수로 확인. $V = 10,000, E = 100,000$ 규모에서 0.3초 이내에 완료.
- 공간 복잡도: $O(V + E)$ — 그래프 인접 리스트 및 방문 순서 배열.
5. 채점 결과 및 통과 인증

← PREVIOUS LOG
[BOJ 11497] 통나무 건너뛰기 - Java (그리디 정렬 & 양방향 지그재그 배치)
NEXT LOG →[BOJ 11400] 단절선 - Java (DFS Spanning Tree & Tarjan 알고리즘)
COMMENTS // GITHUB DISCUSSIONS (GISCUS)