백준 3176번 도로 네트워크
< 백준 3176번 도로 네트워크 - 마포 코딩박 >
사용한 알고리즘: LCA
N개의 도시들과 각 도시를 연결하는 N-1개의 도로에 대한 정보가 입력됩니다. K개의 입력으로 주어지는 도시쌍 a,b 에 대해 a,b를 연결하는 도로들 중 최대, 최소 값을 구하는 문제였습니다.
문제풀이는 다음과 같습니다.
(1) (코드 13~16)
LCA 기본 구현에 쓰이는 'parent[i][k] : i의 2^k 번째 조상' 개념에 더불어 'Value[i][k] : i의 2^k 조상으로 갈 때 <최소길이, 최대길이>' 라는 pair 배열을 추가로 설정해줍니다.
(2) (코드 19~33)
1번 도시를 root라 생각하고 depth[1]=1 라 하고 모든 노드의 depth를 설정해줍니다.
이때 parent[i][0] 는 자신의 부모가 되고, Value[i][0] = <부모까지거리, 부모까지거리> 가 됩니다.
(3) (코드 47~59)
기본적인 LCA 의 parent[i][k] 를 계산하는 과정에서 추가로 Value[i][k] 값도 함께 계산해 줍니다.
(4) (코드 60~97)
K번 입력되는 도시 a,b 의 공통 조상을 찾아가며, 앞서 계산해 둔 Value[i][k] 값을 통해 a,b 사이 도로의 최소, 최대 값을 최신화 해줍니다.
사용한 알고리즘: LCA
N개의 도시들과 각 도시를 연결하는 N-1개의 도로에 대한 정보가 입력됩니다. K개의 입력으로 주어지는 도시쌍 a,b 에 대해 a,b를 연결하는 도로들 중 최대, 최소 값을 구하는 문제였습니다.
문제풀이는 다음과 같습니다.
(1) (코드 13~16)
LCA 기본 구현에 쓰이는 'parent[i][k] : i의 2^k 번째 조상' 개념에 더불어 'Value[i][k] : i의 2^k 조상으로 갈 때 <최소길이, 최대길이>' 라는 pair 배열을 추가로 설정해줍니다.
(2) (코드 19~33)
1번 도시를 root라 생각하고 depth[1]=1 라 하고 모든 노드의 depth를 설정해줍니다.
이때 parent[i][0] 는 자신의 부모가 되고, Value[i][0] = <부모까지거리, 부모까지거리> 가 됩니다.
(3) (코드 47~59)
기본적인 LCA 의 parent[i][k] 를 계산하는 과정에서 추가로 Value[i][k] 값도 함께 계산해 줍니다.
(4) (코드 60~97)
K번 입력되는 도시 a,b 의 공통 조상을 찾아가며, 앞서 계산해 둔 Value[i][k] 값을 통해 a,b 사이 도로의 최소, 최대 값을 최신화 해줍니다.
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 <iostream> | |
#include <utility> // pair | |
#include <algorithm> | |
#include <vector> | |
using namespace std; | |
// town max | |
const int TMAX = 1e5; | |
// dist max ; 10^5 < 2^17 | |
const int DMAX = 17; | |
typedef pair<int, int> pii; | |
int N, K, Depth[TMAX+1]; | |
// parent[i][k] : i의 2^k 번째 조상번호 | |
int parent[TMAX+1][DMAX+1]; | |
// Value[i][k] : i의 2^k번째 조상까지의 pair< 작은길이, 큰길이 > | |
pii Value[TMAX+1][DMAX+1]; | |
// < 연결된 도시 , 연결길이 > | |
vector<pii> arr[TMAX+1]; | |
// 각 노드들의 depth 설정하는 함수 | |
void MakeTree(int curr){ | |
for(auto child: arr[curr]){ | |
int town = child.first; | |
int BaseV = child.second; | |
// 이미 돌아본 도시는 패스 | |
if(Depth[town]!=0) continue; | |
Depth[town] = Depth[curr]+1; | |
// 2^0 번째 부모 저장 | |
parent[town][0] = curr; | |
// 바로 부모까지 작은길이 = 큰길이 | |
Value[town][0] = pii(BaseV,BaseV); | |
MakeTree(town); | |
} | |
} | |
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, w; | |
cin >> a >> b >> w; | |
arr[a].push_back(pii(b,w)); | |
arr[b].push_back(pii(a,w)); | |
} | |
// 1이 root 고 depth[1] = 1 로 설정 | |
Depth[1] = 1; | |
// 각 노드 depth 설정 | |
MakeTree(1); | |
// parent[i][k] 와 Value[i][k] 구하기 | |
for(int k=0; k<=DMAX; ++k){ | |
for(int i=2; i<=N; ++i){ | |
int Father = parent[i][k]; | |
if(Father){ | |
parent[i][k+1] = parent[Father][k]; | |
// 작은길이 업데이트 | |
Value[i][k+1].first = min(Value[i][k].first, Value[Father][k].first); | |
// 큰길이 업데이트 | |
Value[i][k+1].second = max(Value[i][k].second, Value[Father][k].second); | |
} | |
} | |
} | |
cin >> K; | |
for(int i=0; i<K; ++i){ | |
int a, b; | |
cin >> a >> b; | |
int mini = 1000000; | |
int maxi = 0; | |
if(Depth[a]<Depth[b]) swap(a,b); | |
int Diff = Depth[a] - Depth[b]; | |
int cnt = 0; | |
while(Diff){ | |
if(Diff%2==1){ | |
mini = min(mini, Value[a][cnt].first); | |
maxi = max(maxi, Value[a][cnt].second); | |
a = parent[a][cnt]; | |
} | |
Diff/=2; | |
cnt++; | |
} | |
if(a!=b){ | |
for(int k=DMAX; k>=0; k--){ | |
if(parent[a][k]!=parent[b][k]){ | |
mini = min(mini, Value[a][k].first); | |
maxi = max(maxi, Value[a][k].second); | |
a=parent[a][k]; | |
mini = min(mini, Value[b][k].first); | |
maxi = max(maxi, Value[b][k].second); | |
b=parent[b][k]; | |
} | |
} | |
mini = min(mini, Value[a][0].first); | |
maxi = max(maxi, Value[a][0].second); | |
mini = min(mini, Value[b][0].first); | |
maxi = max(maxi, Value[b][0].second); | |
a=parent[a][0]; | |
} | |
cout << mini << ' ' << maxi << '\n'; | |
} | |
return 0; | |
} |
댓글
댓글 쓰기
긴 글 읽어주셔서 감사합니다.
궁금한게 있으시다면 댓글 달아주세요!