반응형
리뷰
그래프의 정보가 주어지고 두 노드간의 거리를 구하는 문제, 루트 노드가 1이 고정이 아니여서 직접 구해주어야 한다.
LCA는 개념만 잘 잡는다면 응용 문제에 적용하는 방법이 어렵지 않은 것 같다.
https://www.acmicpc.net/problem/1761
문제 풀이
- main 함수에 init, ds, pre_process, query 네개의 함수를 순차적으로 실행시켜 문제를 풀었다.
- init 함수에서 n값을 받고 n - 1개의 간선 정보를 tree 벡터 배열에 저장한 뒤 Union 작업을 수행해 준다.
- 1부터 n까지의 노드를 탐색 한 후 자기 자신을 value로 갖는 노드를 찾아 root로 저장한다.
- root 부터 dfs 함수를 통해 각 노드의 깊이와, 루트 노드로 부터의 거리, 자기 자신의 바로 윗 조상을 찾아준다.
- pre_process 함수를 통해 모든 노드의 자기 조상에 대한 정보를 dp 형식으로 저장해 준다.
- query 함수에서 m 값을 입력 받고 총 m개의 쿼리에 대한 출력을 진행해 준다.
- 두 개의 노드를 입력 받고, lca 함수를 통해 두 노드간 최소 공통 조상을 찾아 변수 par에 해당 노드를 저장한다.
- 루트부터 a까지의 비용, b까지의 비용을 더한 후 루트부터 par까지의 비용 * 2만큼을 빼준 뒤 출력한다.
참고 사항
자신의 2^j번째 위 조상을 구하는 점화식 : parent[i][j] = parent[parent[i][j - 1]][j - 1]
lca 함수에서 역순으로 탐색할 경우 LOG - 1부터 0까지 탐색해 주어야 한다, LOG부터 탐색해 주어 오답 처리가 한번 됐었다.
이 문제는 입력 값이 적은 편이지만, 웬만하면 ios::sync_with_stdio(0);, cin.tie(0);를 사용해 주는 것이 좋다.
정답 코드
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int n, m, root;
const int MAX_N = 40001;
const int LOG = 17;
int parent[MAX_N][LOG];
int depth[MAX_N];
int cost[MAX_N];
int nodes[MAX_N];
vector<pair<int, int>> tree[MAX_N];
int Find(int a) {
if (nodes[a] == a) return a;
return nodes[a] = Find(nodes[a]);
}
void Union(int a, int b) {
int A = Find(a);
int B = Find(b);
if (A == B) return;
nodes[B] = A;
}
void init() {
cin >> n;
for (int i = 1; i <= n; i++) nodes[i] = i;
for (int i = 0; i < n - 1; i++) {
int a, b, c; cin >> a >> b >> c;
tree[a].push_back({ b, c });
tree[b].push_back({ a, c });
Union(a, b);
}
for (int i = 1; i <= n; i++) {
if (nodes[i] == i) {
root = i;
break;
}
}
}
void dfs(int node, int p, int d, int c) {
parent[node][0] = p;
depth[node] = d;
cost[node] = c;
for (pair<int, int> next : tree[node]) {
int child = next.first, nc = next.second;
if (child != p) dfs(child, node, d + 1, c + nc);
}
}
void pre_process() {
for (int j = 1; j < LOG; j++) {
for (int i = 1; i <= n; i++) {
if (parent[i][j - 1] != -1) parent[i][j] = parent[parent[i][j - 1]][j - 1];
}
}
}
int lca(int a, int b) {
if (depth[a] < depth[b]) swap(a, b);
int diff = depth[a] - depth[b];
for (int i = 0; i < LOG; i++) {
if ((diff >> i) & 1) a = parent[a][i];
}
if (a == b) return a;
for (int i = LOG - 1; i >= 0; i--) {
if (parent[a][i] != parent[b][i]) {
a = parent[a][i];
b = parent[b][i];
}
}
return parent[a][0];
}
void query() {
cin >> m;
while (m--) {
int a, b; cin >> a >> b;
int par = lca(a, b);
cout << cost[a] + cost[b] - cost[par] * 2 << "\n";
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
init();
dfs(root, -1, 0, 0);
pre_process();
query();
}
728x90
반응형
'알고리즘 공부 > C++' 카테고리의 다른 글
백준 17136번 색종이 붙이기 C++ 브루트포스 알고리즘, DFS, 백트래킹 (0) | 2024.09.02 |
---|---|
백준 17135번 캐슬 디펜스 C++ 브루트포스, DFS, BFS, 구현, 시뮬레이션 (0) | 2024.09.01 |
백준 17070번 파이프 옮기기 1 C++ DFS (0) | 2024.08.30 |
백준 13511번 트리와 쿼리 2 C++ 최소 공통 조상, LCA (0) | 2024.08.30 |
백준 11438번 LCA 2 C++ 최소 공통 조상 (0) | 2024.08.29 |