백준 11438번 LCA2
< 백준 11438번 LCA2 - 마포 코딩박 >
사용한 알고리즘: LCA (최소공통조상)
LCA 를 구현할 줄 알아야 풀 수 있는 문제였습니다.
강산님 블로그 https://blog.naver.com/kks227/220820773477 를 많이 참고하여 풀었습니다. LCA 에 대한 자세한 설명이 있으니 참고하시면 좋을 것 같습니다.
풀이 방법은 다음과 같습니다.
( 사실 LCA 구현법입니다. )
(1) (코드 6~7)
'parent[i][k] : i의 2^k 번째 조상' 라고 설정해줍니다.
(2) (코드 13~22, 36~37)
depth[0]=0 으로 설정하고 각 노드들의 depth를 정하며 트리를 구성합니다.
이때 parent[i][0] 는 바로 위 부모이므로 이를 설정해줍니다.
(3) (코드 39~45)
parent[i][0] 를 설정 해 둔 것을 바탕으로 2^k 번째 부모들을 구해줍니다.
(4) (코드 47~79)
입력으로 두 노드 a, b 를 받으면, 높이를 맞춰 준 후
(이때 a==b가 되면 그 노드가 공통 조상입니다.),
최대 조상 (2^17) 부터 둘의 조상을 비교하면서 내려오며, 둘의 2^k 번째 조상이 다른 경우 해당 위치로 a, b 를 각각 재조정해줍니다.
과정이 끝난 후 a, b 는 같은 부모 밑에 있게 됩니다. 이는 찾고자 하는 최소공통조상입니다.
LCA 구현의 대표적인 문제였습니다.

사용한 알고리즘: LCA (최소공통조상)
LCA 를 구현할 줄 알아야 풀 수 있는 문제였습니다.
강산님 블로그 https://blog.naver.com/kks227/220820773477 를 많이 참고하여 풀었습니다. LCA 에 대한 자세한 설명이 있으니 참고하시면 좋을 것 같습니다.
풀이 방법은 다음과 같습니다.
( 사실 LCA 구현법입니다. )
(1) (코드 6~7)
'parent[i][k] : i의 2^k 번째 조상' 라고 설정해줍니다.
(2) (코드 13~22, 36~37)
depth[0]=0 으로 설정하고 각 노드들의 depth를 정하며 트리를 구성합니다.
이때 parent[i][0] 는 바로 위 부모이므로 이를 설정해줍니다.
(3) (코드 39~45)
parent[i][0] 를 설정 해 둔 것을 바탕으로 2^k 번째 부모들을 구해줍니다.
(4) (코드 47~79)
입력으로 두 노드 a, b 를 받으면, 높이를 맞춰 준 후
(이때 a==b가 되면 그 노드가 공통 조상입니다.),
최대 조상 (2^17) 부터 둘의 조상을 비교하면서 내려오며, 둘의 2^k 번째 조상이 다른 경우 해당 위치로 a, b 를 각각 재조정해줍니다.
과정이 끝난 후 a, b 는 같은 부모 밑에 있게 됩니다. 이는 찾고자 하는 최소공통조상입니다.
LCA 구현의 대표적인 문제였습니다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <bits/stdc++.h> | |
using namespace std; | |
// 노드 수 해봤자 10^5 < 2^17 이므로 어떤점이든 2^17번째 부모까지만 보면됨 | |
const int MAX = 18; | |
int N, M; | |
// parents[i][k] : i의 2^k 번째 부모 | |
int parents[100000][MAX]; | |
// 노드의 깊이 ( 루트는 깊이 0 ) | |
int depth[100000]; | |
// 인접 리스트 | |
vector<int> adj[100000]; | |
// DFS 로 트리 제작, 각 노드들의 2^0 부모 와 깊이 저장 | |
void MakeTreeDFS(int curr){ | |
for(int next: adj[curr]){ | |
if(depth[next]==-1){ | |
parents[next][0] = curr; | |
depth[next] = depth[curr]+1; | |
MakeTreeDFS(next); | |
} | |
} | |
} | |
int main(){ios_base::sync_with_stdio(false); cout.tie(NULL); cin.tie(NULL); | |
cin >> N; | |
for (int i = 0; i < N-1; ++i){ | |
int a, b; | |
cin >> a >> b; | |
a--; | |
b--; | |
adj[a].push_back(b); | |
adj[b].push_back(a); | |
} | |
// parents 값을 -1로 초기화 하고 시작 | |
memset(parents,-1,sizeof(parents)); | |
fill(depth,depth+N, -1); | |
// root 의 깊이는 0 | |
depth[0] = 0; | |
// 트리 만들어~ | |
MakeTreeDFS(0); | |
// i 의 2^j 번째 부모 k가 있으면, i의 2^j * 2 번째 부모는 k의 2^j번째 부모 | |
for (int j = 0; j < MAX-1; ++j){ | |
for (int i = 1; i < N; ++i){ | |
int k = parents[i][j]; | |
if(k!=-1) parents[i][j+1] = parents[k][j]; | |
} | |
} | |
cin >> M; | |
for (int i = 0; i < M; ++i){ | |
int a, b; | |
cin >> a >> b; | |
a--; | |
b--; | |
// depth[a] >= depth[b] 로 생각하기 위해 조정 | |
if(depth[a] < depth[b]) swap(a,b); | |
int diff = depth[a] - depth[b]; | |
// a 와 b 를 같은 높이로 맞춰주기 | |
int j = 0; | |
while(diff){ | |
if(diff%2) { | |
a = parents[a][j]; | |
} | |
j++; | |
diff/=2; | |
} | |
// a==b 이면 a=b 가 공통조상이겠죠. | |
if(a!=b){ | |
// 2^17, 2^16, ... 2, 1 번째 부모를 비교 | |
// 가장 중요한 스킬!!!!!!!!!!!1 | |
for (int j = MAX-1; j>=0; j--){ | |
// 2^j번째 조상이 다른게 나오면 a, b 를 각각의 2^j번째 조상으로 위치변경 | |
if(parents[a][j]!=parents[b][j]){ | |
a = parents[a][j]; | |
b = parents[b][j]; | |
} | |
} | |
// 위 과정이 끝나면 최종 a, b 는 같은 부모 아래 있다. | |
a = parents[a][0]; | |
} | |
cout << a+1 << '\n'; | |
} | |
return 0; | |
} |
아.... 저는 자꾸 틀렸다고 나오네요.
답글삭제혹시, 아래 제 코드의 어디에서 잘못되었는지 한번 봐주실 수 있을까요? ㅠ ㅠ
#include
#include
#include
#include
#include
using namespace std;
#define NMAX 100002
vector Edge[NMAX];
int Parent[20][NMAX];
int depth[NMAX];
int N, M;
int getLCA(int n1, int n2)
{
if (depth[n1] > depth[n2])
swap(n1, n2);
int mx = log2(N) + 1;
for (int i = mx; i >= 0; i--)
{
if (depth[n2] - depth[n1] >= (1 << i))
{
n2 = Parent[i][n2];
}
}
if (n1 == n2)
return n1;
for (int i = mx; i >= 0; i--)
{
if (Parent[i][n1] != Parent[i][n2])
{
n1 = Parent[i][n1];
n2 = Parent[i][n2];
}
}
return Parent[0][n1];
}
int main()
{
freopen("013_백준_11438_LCA 2.txt", "r", stdin);
scanf("%d", &N);
//Init
for (int i = 1; i <= N; i++)
{
Parent[0][i] = -1;
}
for (int i = 0; i < N - 1; i++)
{
int s, e;
scanf("%d %d", &s, &e);
Edge[s].emplace_back(e);
Edge[e].emplace_back(s);
}
queue qu;
qu.emplace(1);
Parent[0][1] = 0;
while (!qu.empty())
{
int cn = qu.front();
qu.pop();
for (auto& nn : Edge[cn])
{
if (Parent[0][nn] == -1)
{
Parent[0][nn] = cn;
depth[nn] = depth[cn] + 1;
qu.emplace(nn);
}
}
}
int mx = log2(N) + 1;
for (int i = 1; i <= N; i++)
{
for (int k = 1; k < mx; k++)
{
int par = Parent[k - 1][i];
Parent[k][i] = Parent[k - 1][par];
}
}
scanf("%d", &M);
for (int i = 0; i < M; i++)
{
int u, v;
scanf("%d %d", &u, &v);
printf("%d\n", getLCA(u, v));
}
return 0;
}