문제 - https://www.acmicpc.net/problem/11438
11438번: LCA 2
첫째 줄에 노드의 개수 N이 주어지고, 다음 N-1개 줄에는 트리 상에서 연결된 두 정점이 주어진다. 그 다음 줄에는 가장 가까운 공통 조상을 알고싶은 쌍의 개수 M이 주어지고, 다음 M개 줄에는 정
www.acmicpc.net
import java.io.*;
import java.util.*;
public class Main {
static BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter bw= new BufferedWriter(new OutputStreamWriter(System.out));
static StringBuilder sb = new StringBuilder();
static StringTokenizer st;
static int N, M, K;
static int[] depth;
static int[][] arr;
static ArrayList<Integer>[] tree;
public static void main(String[] args) throws Exception {
N = Integer.parseInt(br.readLine());
depth = new int[N+1];
tree = new ArrayList[N+1];
while(Math.pow(2, K)<=N)
K++;
arr = new int[N+1][K]; // arr[i][j] : i번째 노드의 2^j번째 부모
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());
if (tree[a]==null)
tree[a] = new ArrayList<>();
if (tree[b]==null)
tree[b] = new ArrayList<>();
tree[a].add(b);
tree[b].add(a);
}
init_dep(1, 1); // init_dep(a, b) -> a번째 노드의 depth를 b로 만듬
for (int k = 1; k < K; k++) {
for (int v = 1; v <= N; v++) {
arr[v][k] = arr[ arr[v][k-1] ][ k-1 ]; // "v"의 "2^k번째 부모"는 "v의 2^(k-1)번째 부모"의 "2^(k-1)번째 부모"
}
}
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());
sb.append(lca(a, b)+"\n"); // lca(a, b) -> a와 b의 최소 공통 조상 찾기
}
bw.write(sb.toString());
bw.flush();
bw.close();
br.close();
}
static int lca(int a, int b){
if(depth[a]<depth[b]){ // 무조건 a가 더 트리의 아랫쪽에 위치하도록 바꿔주기
int tmp = a;
a = b;
b = tmp;
}
for (int i = K-1; depth[a]>depth[b]; i--) { // 제일 아랫쪽에서부터 올라오면서
if(Math.pow(2, i) <= depth[a]-depth[b]) // 높이 차이가 2의 거듭제곱보다 작으면
a = arr[a][i]; // 높이 맞춰주기
}
if (a==b) // 높이가 같은데 값도 같으면
return a; // 바로 리턴
for (int i = K-1; i >= 0; i--) { // 같은 높이에서 2^i만큼 높이를 올라가면서
if(arr[a][i]!=arr[b][i]){ // 서로 다르면
a = arr[a][i]; // 갱신
b = arr[b][i];
}
}
return arr[a][0]; // 공통조상 바로 밑이므로, 첫번째 조상 리턴
}
static void init_dep(int cur, int dep){
depth[cur] = dep;
for(int next : tree[cur]){
if(depth[next]==0){
arr[next][0] = cur;
init_dep(next, dep+1);
}
}
}
}
한번 풀어봤던 문제지만, 레퍼런스없이 맨땅에 구현하기는 정말 쉽지 않은 문제인것 같다.
충분한 구현계획을 잡고나서 실제 코드로 옮기는 습관을 들이자!
'공부 > algorithm' 카테고리의 다른 글
BOJ 감시 피하기(18428) - Java (0) | 2021.09.24 |
---|---|
BOJ 탈출(3055) - Java (0) | 2021.09.15 |
BOJ AC(5430) - Java (0) | 2021.09.13 |
BOJ 고스택(3425) - Java (0) | 2021.09.13 |
BOJ 사다리 조작(15684) - Java (0) | 2021.09.07 |