💡Problem Solving/BOJ
[BOJ 11437] LCA (Java)
gom20
2021. 10. 24. 12:33
#문제
https://www.acmicpc.net/problem/11437
11437번: LCA
첫째 줄에 노드의 개수 N이 주어지고, 다음 N-1개 줄에는 트리 상에서 연결된 두 정점이 주어진다. 그 다음 줄에는 가장 가까운 공통 조상을 알고싶은 쌍의 개수 M이 주어지고, 다음 M개 줄에는 정
www.acmicpc.net
#풀이
트리의 두 노드가 주어지고 최소 공통 조상을 찾는 문제이다. (Lowest Common Ancestor)
입력받은 노드의 연관 관계를 인접 노드 리스트로 저장해둔다.
root node를 시작으로 dfs로 모든 node의 parent와 depth를 갱신한다.
그리고 입력 받은 두 점의 depth를 비교하여
depth의 차이가 있을 경우 depth가 더 큰 node 값을 해당 node의 parent로 갱신하면서
depth 가 같아질 때까지 반복한다.
depth가 동일해졌다면 이제 공통조상을 찾아야 한다.
두 점의 값부터 ~ 두 점의 parent를 차례대로 비교하면서
node가 같아지는 순간, 해당 node 값이 최소 공통 조상이 된다.
#소스코드
package lca;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.StringTokenizer;
public class BOJ3584 {
public static int N, M;
public static int[] parent;
public static int[] depth;
public static boolean[] calculated; //depth 계산 여부
public static ArrayList<Integer>[] adjs;
public static void pro() throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
parent = new int[N+1];
depth = new int[N+1];
calculated = new boolean[N+1];
adjs = new ArrayList[N+1];
for(int i = 0; i <= N; i++) adjs[i] = new ArrayList<Integer>();
for(int i = 0; i < N-1; i++){
StringTokenizer st = new StringTokenizer(br.readLine());
int n1 = Integer.parseInt(st.nextToken());
int n2 = Integer.parseInt(st.nextToken());
adjs[n1].add(n2);
adjs[n2].add(n1);
}
// dfs로 parent, depth 업데이트 하기
// root, depth
dfs(1, 1, 0);
StringBuilder sb = new StringBuilder();
M = Integer.parseInt(br.readLine());
for(int i = 0; i < M; i++){
StringTokenizer st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
sb.append(findLCA(a, b) + "\n");
}
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
bw.write(sb.toString());
bw.flush();
}
public static int findLCA(int a, int b){
// depth를 비교
while(depth[a] > depth[b]){
// a의 depth가 더 크다면 a의 parent depth로 다시 비교
// depth가 같아질 때까지 반복
a = parent[a];
}
while(depth[b] > depth[a]){
b = parent[b];
}
// a 와 b의 depth가 같아졌다면
// 차례대로 올라가면서 공통조상을 찾는다
while(a != b){
a = parent[a];
b = parent[b];
}
return a;
}
public static void dfs(int n, int p, int d){
parent[n] = p;
depth[n] = d;
calculated[n] = true;
for(int adj : adjs[n]){
if(calculated[adj]) continue;
dfs(adj, n,d+1);
}
}
public static void main(String[] args) throws Exception {
pro();
}
}