[백준 11438 : JAVA] LCA 2 / 최소 공통 조상
문제

풀이
LCA(Lowest Common Acestor_최소 공통 조상) 알고리즘을 사용하는 기본 유형의 문제다.
해당 문제에서 주의깊게 봐둬야할 건 각 노드의 2^i 번 째 조상노드를 테이블에 저장하기 위해 DP를 사용한 점화식이다.
- DFS 탐색을 통해 각 노드별 depth를 구해 배열에 저장하고, 각 노드의 첫 번째 조상노드를 parent 배열에 담는다. (DP 사전준비)
- DP 알고리즘을 통해 각 노드의 모든 2^i 번 째 조상노드를 구해 parent 배열에 저장한다.
- LCA(a, b)에서 a와 b의 깊이를 맞춘 후, 차례로 2^i 번 째 조상노드를 구해가며 최소 공통 조상을 찾는다.
위의 2번을 보면 DP를 통해 각 노드의 2^i 번 째 조상노드를 저장한다고 되어 있는데, 해당 코드를 보자.
for (int i = 1; i < depth; i++) { for (int j = 1; j <= N; j++) { parent[j][i] = parent[ parent[j][i - 1] ][i - 1]; } }
A 정점의 2^1 번 째 조상은 A 정점의 2^0 번 째 조상노드의 2^0 번 째 조상과 같다.
A 정점의 2^1 번 째 조상노드 = A 정점의 2^0 번 째 조상노드의 2^0 번 째 조상노드
코드
import java.io.*; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; public class Main { private static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); private static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); private static int N, M, K; private static List<List<Integer>> tree; private static int[] depth; private static int[][] parents; public static void main(String[] args) throws IOException { StringTokenizer st; N = Integer.parseInt(br.readLine()); tree = new ArrayList<>(); for (int i = 0; i < N + 1; i++) tree.add(new ArrayList<>()); for (int i = 0; i < N - 1; i++) { st = new StringTokenizer(br.readLine()); int a = Integer.parseInt(st.nextToken()); int b = Integer.parseInt(st.nextToken()); tree.get(a).add(b); tree.get(b).add(a); } int tmp = 1; K = 0; while (tmp <= N) { // 최대 depth 알아내기. tmp <<= 1; K++; } depth = new int[N + 1]; parents = new int[N + 1][K]; dfs(1, 1); fillParents(); M = Integer.parseInt(br.readLine()); for (int i = 0; i < M; i++) { st = new StringTokenizer(br.readLine()); int a = Integer.parseInt(st.nextToken()); int b = Integer.parseInt(st.nextToken()); int lca = lca(a, b); bw.write(lca + "\n"); } bw.flush(); bw.close(); br.close(); } private static int lca(int a, int b) { if (depth[a] < depth[b]) { // 깊이가 낮은 쪽을 기준으로 맞춘다. int temp = a; a = b; b = temp; } //더 깊은 a를 2승씩 점프하며 두 노드의 depth를 맞춘 후, 맞춘 depth의 조상 노드로 대체한다. for (int i = K - 1; i >= 0; i--) { if (Math.pow(2, i) <= depth[a] - depth[b]) { a = parents[a][i]; // a를 2^i 번 째 조상 노드로 대체한다. } } // depth 맞춘 후 대체한 조상 노드가 b와 같다면. 즉, a의 조상노드가 b라면 종료한다. if (a == b) return a; // 이제 두 노드는 같은 depth를 가지기 때문에 // 같이 2승씩 점프시키며 공통부모 바로 아래까지 올린다. for (int i = K - 1; i >= 0; i--) { if (parents[a][i] != parents[b][i]) { a = parents[a][i]; b = parents[b][i]; } } return parents[a][0]; } private static void fillParents() { for (int i = 1; i < K; i++) { // DP를 이용해 각 노드별 2^K 번 째 조상 노드를 저장한다. for (int j = 1; j <= N; j++) { parents[j][i] = parents[ parents[j][i - 1] ][i - 1]; } } } private static void dfs(int node, int cnt) { depth[node] = cnt; for (Integer next : tree.get(node)) { if (depth[next] == 0) { dfs(next, cnt + 1); parents[next][0] = node; } } } }
'Algorithm > Baekjoon' 카테고리의 다른 글
[백준 17141 : JAVA] 연구소 2 / BFS + 조합 (0) | 2020.09.27 |
---|---|
[백준 9466 : JAVA] 텀 프로젝트 / DFS (0) | 2020.09.23 |
[백준 13418 : JAVA] 학교 탐방하기 / MST (0) | 2020.09.09 |
[백준 2206 : JAVA] 벽 부수고 이동하기 / BFS (0) | 2020.09.08 |
[백준 9370 : JAVA] 미확인 도착지 / 다익스트라 (0) | 2020.08.28 |
댓글
이 글 공유하기
다른 글
-
[백준 17141 : JAVA] 연구소 2 / BFS + 조합
[백준 17141 : JAVA] 연구소 2 / BFS + 조합
2020.09.27 -
[백준 9466 : JAVA] 텀 프로젝트 / DFS
[백준 9466 : JAVA] 텀 프로젝트 / DFS
2020.09.23 -
[백준 13418 : JAVA] 학교 탐방하기 / MST
[백준 13418 : JAVA] 학교 탐방하기 / MST
2020.09.09 -
[백준 2206 : JAVA] 벽 부수고 이동하기 / BFS
[백준 2206 : JAVA] 벽 부수고 이동하기 / BFS
2020.09.08
댓글을 사용할 수 없습니다.