백준/트리

11437 LCA

have a good time 2022. 5. 8. 22:38

 

1. 풀이

 

 

 

다른 사람 블로그를 참고했다.

 

일단 그림으로 설명하겠다.

 

 

<그림1>

문제 예제에 6번 노드와 11번 노드의 부모를 찾으라고 되어있다.

이때, 6번 노드와 11번 노드의 level 이 다르다.

트리에서 level 이란, 루트 노드로부터 깊이를 의미하는데, 루트 노드의 level = 1이다.

이때 level 이 더 큰 11번 노드와 관련해서 변화를 준다.

=> 11번 노드의 부모 노드를 타고 이동하면서 노드 6과 level 이 같아지는 노드 번호를 찾는다.

 

 

 

<그림2>

5번 노드와 6번 노드의 level 이 같다.

이때부터는 5번, 6번 노드의 각 부모 노드를 타고 올라가면서 그 값이 같아지는 경우를 찾으면 된다.

5번 노드의 부모 노드와, 6번 노드의 부모 노드가 2로 같다.

정답은 2가 된다.

 

<그림3>

 

위에서는 쉽게 풀렸지만, 다른 경우를 생각해보자.

9번, 11번 노드는 level 이 같다.

하지만 9번 노드의 부모는 4, 11번 노드의 부모는 5이다.

서로 같지 않으므로 부모 노드를 한 번 더 따져봐야 한다.

4번, 5번 노드의 부모노드는 2이므로 같아졌다.

이 경우도 정답은 2가 된다.

 

이런식으로 해결하면 된다.

 

 

 

2. 최종 코드

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class Main {
	
	static int parents[];
	static int depth[];
	static boolean visit[];
	static ArrayList<ArrayList<Integer>> tree;

	public static void main(String[] args) throws IOException {
				
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int N = Integer.parseInt(br.readLine());
		tree  = new ArrayList<>();
		
		for(int i=0; i<=N; i++) {
			tree.add(new ArrayList<>());
		}
		
		parents = new int[N+1];
		depth = new int[N+1];
		visit = new boolean[N+1];
		
		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());
			
			tree.get(n1).add(n2);
			tree.get(n2).add(n1);
		}
		
		
		dfs(1,0, 1);
			
		int M = Integer.parseInt(br.readLine());
		
		for(int i=0; i<M; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine(), " " );
			int n1 = Integer.parseInt(st.nextToken());
			int n2 = Integer.parseInt(st.nextToken());
			int result = solve(n1, n2);
			System.out.println(result);
		}
	}
	
	
	public static void dfs(int a, int b, int count) {
		
		if(!visit[a]) {
			visit[a] = true;
			depth[a] = count ;
			parents[a] = b;
			
			for(int i=0; i<tree.get(a).size(); i++) {
				int next = tree.get(a).get(i);
				dfs(next, a, count+1);
			}
		}
	}
	
	
	public static int solve(int a, int b) {
	
		int depth1 = depth[a];
		int depth2 = depth[b];
		
		while(depth1 != depth2) {
			if(depth1> depth2) {
			
				a = parents[a];
				depth1--;
			}else {
				b = parents[b];
				depth2--;
			}
		}
	
		while(a!=b) {
			a= parents[a];
			b= parents[b];
		
		}
		
			return a;		
	}
}

 

3. 코드 설명

 

 

코드에서 사용된 메서드에 대해 설명하겠다.

1. dfs 메서드

 

트리 각 노드 부모노드는 parents 배열에 입력해준다.

level 값은 depth 배열에 입력해준다.

 

예를 들어 노드 6의 부모노드는 2, level은 3이므로,

parents[6] = 2, depth[6] = 3

 

2. solve 메서드

 

위에서 설명한 것처럼,

1) 6번 노드, 11번 노드의 level 값 (depth 배열 값)을 비교한다.

=> depth[6] = 3 < depth[11] = 4 

값이 더 큰 11번 노드와 관련해 변화를 준다.

 

2) 11번 노드의 부모 노드를 찾는다. => 5

5번과 6번 노드의 level 값을 비교한다.

depth[5] = depth[6] = 3

 

3) 3으로 값이 같으므로 5번, 6번 노드의 부모노드가 같은지 확인한다.

부모 노드가 같으면, 최종 정답이 된다. => 즉 가장 가까운 공통 조상

부모 노드가 모두 2이므로 정답이다.

 

참고 블로그 :

https://loosie.tistory.com/360

 

[BOJ] 백준 11437번 LCA (Java)

#11437 LCA 난이도 : 골드 3 유형 : 트리 / LCA 11437번: LCA 첫째 줄에 노드의 개수 N이 주어지고, 다음 N-1개 줄에는 트리 상에서 연결된 두 정점이 주어진다. 그 다음 줄에는 가장 가까운 공통 조상을 알

loosie.tistory.com