백준 1761번 정점들의 거리
< 백준 1761번 정점들의 거리 - 마포 코딩박 >
사용한 알고리즘: LCA
트리에서 두 점 사이의 최단거리를 구하는 문제였습니다.
두 점의 공통 조상까지의 거리를 구하고 그 거리를 구해 문제를 해결했습니다.
문제 풀이는 다음과 같습니다.
(1) 두 노드와 입력되는 거리 a, b, cost 를 pair< 노드, 거리 > 형식으로 저장합니다.
양방향 이므로 a에 <b, cost> , b에 <a, cost> 를 각각 자식으로 저장했습니다.
(2) 1번 노드를 Root 으로 설정하고, 트리를 구현합니다.
( LCA 구현이 어려운 분들은 강산님의 블로그
https://blog.naver.com/kks227/220820773477 를 참고해주세요)
(3) 공통 조상으로 가는 LCA 를 구현하면서, 그 과정에서 지나는 노드와의 거리 ( 과정 (1)에서 저장한 < 노드, 거리> 에서 거리값 )을 더해줍니다.
LCA 를 사용하는 문제라고 쉽게 알 수 있었습니다. LCA 구현을 잘 하는게 중요한 문제였습니다.
사용한 알고리즘: LCA
트리에서 두 점 사이의 최단거리를 구하는 문제였습니다.
두 점의 공통 조상까지의 거리를 구하고 그 거리를 구해 문제를 해결했습니다.
문제 풀이는 다음과 같습니다.
(1) 두 노드와 입력되는 거리 a, b, cost 를 pair< 노드, 거리 > 형식으로 저장합니다.
양방향 이므로 a에 <b, cost> , b에 <a, cost> 를 각각 자식으로 저장했습니다.
(2) 1번 노드를 Root 으로 설정하고, 트리를 구현합니다.
( LCA 구현이 어려운 분들은 강산님의 블로그
https://blog.naver.com/kks227/220820773477 를 참고해주세요)
(3) 공통 조상으로 가는 LCA 를 구현하면서, 그 과정에서 지나는 노드와의 거리 ( 과정 (1)에서 저장한 < 노드, 거리> 에서 거리값 )을 더해줍니다.
LCA 를 사용하는 문제라고 쉽게 알 수 있었습니다. 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; | |
const int MAX = 40001; | |
// pair< 번호, 거리 > | |
typedef pair<int, int> pii; | |
int N, M, depth[MAX]; | |
pii parent[MAX][17]; | |
vector<pii> adj[MAX]; | |
void MakeTree(int curr){ | |
for (auto child: adj[curr]){ | |
if(depth[child.first]!=-1) continue; | |
parent[child.first][0] = pii(curr,child.second); | |
depth[child.first] = depth[curr]+1; | |
MakeTree(child.first); | |
} | |
} | |
int main(){ios_base::sync_with_stdio(false); cout.tie(NULL); cin.tie(NULL); | |
memset(depth,-1,sizeof(depth)); | |
cin >> N; | |
for (int i = 0; i < N-1; ++i){ | |
int a, b, cost; | |
cin >> a >> b >> cost; | |
adj[a].push_back(pii(b,cost)); | |
adj[b].push_back(pii(a,cost)); | |
} | |
depth[1] = 0; | |
MakeTree(1); | |
for (int j = 0; j < 17; ++j){ | |
for (int i = 2; i <= N; ++i){ | |
int k = parent[i][j].first; | |
if(k!=0) parent[i][j+1] = pii(parent[k][j].first, parent[k][j].second+parent[i][j].second); | |
} | |
} | |
cin >> M; | |
for (int i = 0; i < M; ++i){ | |
int a, b; | |
int ans = 0; | |
cin >> a >> b; | |
// LCA 구현 | |
// a 의 depth 를 더 크게 생각하고싶다. | |
if(depth[a] < depth[b]) swap(a,b); | |
int diff = depth[a] - depth[b]; | |
int j = 0; | |
while(diff){ | |
if(diff%2) { | |
ans += parent[a][j].second; | |
a = parent[a][j].first; | |
} | |
j++; | |
diff/=2; | |
} | |
if(a!=b){ | |
// 2^16, ... 2, 1 번째 부모를 비교 | |
// 가장 중요한 스킬!!!!!!!!!!!1 | |
for (int j = 16; j>=0; j--){ | |
// 2^j번째 조상이 다른게 나오면 a, b 를 각각의 2^j번째 조상으로 위치변경 | |
if(parent[a][j].first!=parent[b][j].first){ | |
ans+=parent[a][j].second; | |
ans+=parent[b][j].second; | |
a = parent[a][j].first; | |
b = parent[b][j].first; | |
} | |
} | |
// 위 과정이 끝나면 최종 a, b 는 같은 부모 아래 있다. | |
ans+=parent[b][0].second; | |
ans+=parent[a][0].second; | |
a = parent[a][0].first; | |
} | |
cout << ans << '\n'; | |
} | |
return 0; | |
} |
댓글
댓글 쓰기
긴 글 읽어주셔서 감사합니다.
궁금한게 있으시다면 댓글 달아주세요!