https://www.acmicpc.net/problem/11437
11437번: LCA
첫째 줄에 노드의 개수 N이 주어지고, 다음 N-1개 줄에는 트리 상에서 연결된 두 정점이 주어진다. 그 다음 줄에는 가장 가까운 공통 조상을 알고싶은 쌍의 개수 M이 주어지고, 다음 M개 줄에는 정
www.acmicpc.net
코드설명
트리, DP, LCA 문제입니다.
트리에서 두 노드의 최소 공통 조상(Lowest Common Ancestor, LCA)를 찾는 문제입니다.
이 문제같은경우, BFS와 DFS로 방식으로 각각 구현해보았습니다.
문제의 핵심 로직입니다.
1.먼저 사용할 데이터입니다. depth[] : 트리에서 각 노드의 깊이를 의미합니다., parent[] : 트리에서 각 노드의 부모를 의미합니다, visited[] : 트리에서 방문여부를 확인합니다.
2. DFS를 사용하여 각 노드의 깊이(depth)와 부모 노드(parent)를 설정합니다.
3. 최소 공통 조상(LCA) (Finding Lowest Common Ancestor)를 통해 주어진 두 노드의 깊이를 비교하여 높이를 맞추고, 그 후에 공통 조상을 찾습니다.
코드
DFS 로 푼 코드 + getLCA 코드의 로직 수정
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.LinkedList; import java.util.Queue; import java.util.StringTokenizer; public class Main { public static int N, M; public static int[][] map; public static StringBuilder sb = new StringBuilder(); public static ArrayList<ArrayList<Integer>> graph = new ArrayList<ArrayList<Integer>>(); public static int[] depth; public static int[] parent; public static boolean[] visited; public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); for(int i=0;i<=N;i++) { graph.add(new ArrayList<Integer>()); } depth = new int[N+1]; parent = new int[N+1]; visited = new boolean[N+1]; 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()); graph.get(a).add(b); graph.get(b).add(a); } visited[1] = true; dfs(0, 1, 1); st = new StringTokenizer(br.readLine()); M = Integer.parseInt(st.nextToken()); 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(getLCA(a,b)).append("\n"); } System.out.println(sb.toString()); } public static int getLCA(int a, int b) { //최소공통조상을 구합니다. int aH = depth[a]; int bH = depth[b]; while(aH > bH) { //서로의 높이를 맞춰줍니다. a = parent[a]; aH-=1; } while(aH < bH) { b = parent[b]; bH -=1; } //같은 조상이 나올때까지 한칸씩 올라가비다. while(a != b) { a = parent[a]; b = parent[b]; } return a; } public static void dfs(int level, int curNode, int parentNode) { parent[curNode] = parentNode; depth[curNode] = level; for(int i=0; i<graph.get(curNode).size(); i++) { int nextNode = graph.get(curNode).get(i); if(visited[nextNode] == false) { visited[nextNode] = true; dfs(level + 1, nextNode, curNode); } } } }
BFS로 푼 코드
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.LinkedList; import java.util.Queue; import java.util.StringTokenizer; public class Main { public static int N, M; public static int[][] map; public static StringBuilder sb = new StringBuilder(); public static ArrayList<ArrayList<Integer>> graph = new ArrayList<ArrayList<Integer>>(); public static int[] depth; public static int[] parent; public static boolean[] visited; public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); for(int i=0;i<=N;i++) { graph.add(new ArrayList<Integer>()); } depth = new int[N+1]; parent = new int[N+1]; visited = new boolean[N+1]; 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()); graph.get(a).add(b); graph.get(b).add(a); } BFS(1); st = new StringTokenizer(br.readLine()); M = Integer.parseInt(st.nextToken()); 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(getLCA(a,b)).append("\n"); } System.out.println(sb.toString()); } public static int getLCA(int a, int b) { //최소공통조상을 구합니다. if(depth[a] < depth[b]) { //만약 b의 depth가 a보다 더 깊다면, a와 b를 swap 시켜서 a를 더 깊게 만듭니다. 무조건적으로 a가 더 깊게 만들어서 올라오도록 할것입니다. int temp = a; a = b; b = temp; } while(depth[a] != depth[b]) { //만약 a와 b의 depth가 다르다면, a를 부모노드로 1칸씩 옮겨주며 깊이를 맞춥니다. a = parent[a]; } //같은 조상이 나올때까지 한칸씩 올라가비다. while(a != b) { a = parent[a]; b = parent[b]; } return a; } public static void BFS(int startNode) { Queue<Integer> q = new LinkedList<>(); q.offer(startNode); visited[startNode] = true; depth[startNode] = 1; parent[startNode] = startNode; int level = 0; //현재 높이를 저장합니다. int q_size = q.size(); int cnt = 0; while(!q.isEmpty()) { int temp = q.poll(); for(int i=0;i<graph.get(temp).size();i++) { int child = graph.get(temp).get(i); if(visited[child] == false) { visited[child] = true; parent[child] = temp; //부모노드를 저장합니다. depth[child] = level; //깊이를 저장합니다. q.offer(child); } } cnt += 1; if(cnt == q_size) { cnt = 0; q_size = q.size(); level += 1; } } } }
'알고리즘 > Tree' 카테고리의 다른 글
[백준] 4803 트리 - 트리(Tree) + DFS(깊이우선탐색) + 분리집합(disjoint set) + 유니온파인드(Union Find) JAVA (0) | 2023.11.23 |
---|---|
[백준] 1949 우수 마을 - DP + Tree DP(트리 다이나믹프로그래밍) JAVA (0) | 2023.11.16 |
[백준] 2533 사회망 서비스(SNS) - 트리(Tree) + DP JAVA (0) | 2023.11.12 |
[백준] 1167 트리의 지름 - DFS(깊이우선탐색) + 트리(Tree) + 시간초과 JAVA (0) | 2023.08.27 |
[백준] 1240 노드사이의 거리 - 트리(Tree) + DFS JAVA (0) | 2023.08.14 |