From 28233bdfc48bf70f026a121ca6654ae41c64b903 Mon Sep 17 00:00:00 2001 From: SSUM <116950962+ssum21@users.noreply.github.com> Date: Tue, 4 Mar 2025 17:35:54 +0900 Subject: [PATCH] [Gold III] Title: LCA, Time: 396 ms, Memory: 50396 KB -BaekjoonHub --- 백준/Gold/11437. LCA/LCA.py | 84 ++++++++++++++++++++++++++++++++++ 백준/Gold/11437. LCA/README.md | 30 ++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 백준/Gold/11437. LCA/LCA.py create mode 100644 백준/Gold/11437. LCA/README.md diff --git a/백준/Gold/11437. LCA/LCA.py b/백준/Gold/11437. LCA/LCA.py new file mode 100644 index 0000000..d949bdf --- /dev/null +++ b/백준/Gold/11437. LCA/LCA.py @@ -0,0 +1,84 @@ +import sys +from collections import deque + +input = sys.stdin.readline +print = sys.stdout.write + +# 1. 그래프 입력 +N = int(input()) +tree = [[] for _ in range(N+1)] +for _ in range(N-1): + s, e = map(int, input().split()) + tree[s].append(e) + tree[e].append(s) + +# 2. kmax 계산 (2^k >= N 만족하는 k) +kmax = 0 +temp = 1 +while temp <= N: + temp <<= 1 + kmax += 1 + +depth = [0] * (N+1) +visited = [False] * (N+1) +parent = [[0] * (N+1) for _ in range(kmax+1)] + +# 3. BFS로 depth, parent[0] 채우기 +def BFS(start): + queue = deque([start]) + visited[start] = True + level = 1 + count = 0 + now_size = 1 + + while queue: + node = queue.popleft() + for nxt in tree[node]: + if not visited[nxt]: + visited[nxt] = True + queue.append(nxt) + parent[0][nxt] = node # 바로 윗 조상 기록 + depth[nxt] = level + count += 1 + if count == now_size: + count = 0 + now_size = len(queue) + level += 1 + +BFS(1) # 루트(1번 노드)부터 BFS + +# 4. parent[k][v]: v에서 2^k 위에 있는 조상 전처리 +for k in range(1, kmax+1): + for v in range(1, N+1): + parent[k][v] = parent[k-1][ parent[k-1][v] ] + +# 5. LCA(최소공통조상) 함수 +def LCA(a, b): + # depth[a] <= depth[b]가 되도록 조정 + if depth[a] > depth[b]: + a, b = b, a + + # b를 a와 depth가 같아질 때까지 끌어올리기 + diff = depth[b] - depth[a] + for k in range(kmax+1): + if diff & (1 << k): + b = parent[k][b] + + # 만약 a와 b가 같다면 그게 LCA + if a == b: + return a + + # 가장 높은 레벨부터, 부모가 서로 다를 때만 끌어올리기 + for k in range(kmax, -1, -1): + if parent[k][a] != parent[k][b]: + a = parent[k][a] + b = parent[k][b] + + # 마지막에 한 칸(직계 부모) 올리면 LCA + return parent[0][a] + +# 6. 쿼리 처리 +M = int(input()) +for _ in range(M): + a, b = map(int, input().split()) + print(str(LCA(a, b)) + '\n') diff --git a/백준/Gold/11437. LCA/README.md b/백준/Gold/11437. LCA/README.md new file mode 100644 index 0000000..0526598 --- /dev/null +++ b/백준/Gold/11437. LCA/README.md @@ -0,0 +1,30 @@ +# [Gold III] LCA - 11437 + +[문제 링크](https://www.acmicpc.net/problem/11437) + +### 성능 요약 + +메모리: 50396 KB, 시간: 396 ms + +### 분류 + +그래프 이론, 최소 공통 조상, 트리 + +### 제출 일자 + +2025년 3월 4일 17:35:16 + +### 문제 설명 + +

N(2 ≤ N ≤ 50,000)개의 정점으로 이루어진 트리가 주어진다. 트리의 각 정점은 1번부터 N번까지 번호가 매겨져 있으며, 루트는 1번이다.

+ +

두 노드의 쌍 M(1 ≤ M ≤ 10,000)개가 주어졌을 때, 두 노드의 가장 가까운 공통 조상이 몇 번인지 출력한다.

+ +### 입력 + +

첫째 줄에 노드의 개수 N이 주어지고, 다음 N-1개 줄에는 트리 상에서 연결된 두 정점이 주어진다. 그 다음 줄에는 가장 가까운 공통 조상을 알고싶은 쌍의 개수 M이 주어지고, 다음 M개 줄에는 정점 쌍이 주어진다.

+ +### 출력 + +

M개의 줄에 차례대로 입력받은 두 정점의 가장 가까운 공통 조상을 출력한다.

+