알고리즘/문제 풀이
1167번: 트리의 지름
Themion
2021. 12. 7. 15:25
https://www.acmicpc.net/problem/1167
1167번: 트리의 지름
트리가 입력으로 주어진다. 먼저 첫 번째 줄에서는 트리의 정점의 개수 V가 주어지고 (2 ≤ V ≤ 100,000)둘째 줄부터 V개의 줄에 걸쳐 간선의 정보가 다음과 같이 주어진다. 정점 번호는 1부터 V까지
www.acmicpc.net
1. 트리의 루트 노드에서 가장 거리가 먼 노드 a에 대해, 노드 a로부터 가장 거리가 먼 노드 b까지의 거리가 트리의 지름이 된다.
#include <iostream>
#include <vector>
using namespace std;
typedef pair<int, int> edge;
#define MAX 100001
#define _node first
#define _dist second
int N, ret = 0;
edge ans = { 0, 0 };
vector<edge> tree[MAX];
int max(int a, int b) { return a > b ? a : b; }
// 루트 노드에서 부모 노드가 parent인 노드 node까지의 거리가 dist일 때
// node에서 리프 노드까지의 거리를 계산
void dfs(int node, int parent, int dist) {
// node의 자식 노드에서 dfs를 실행
for (auto e : tree[node]) if (e._node != parent)
dfs(e._node, node, dist + e._dist);
// 이전까지 찾아낸 거리보다 현재 거리가 더 멀다면
// 현재 노드와 거리를 루트 노드에서 가장 먼 노드와 그 거리로 설정
if (ans._dist < dist) ans = { node, dist };
}
int main () {
// 입출력 속도 향상
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
// N: 노드의 수, node: 연결된 노드를 입력받을 때 쓸 각 노드의 인덱스
// child: 각 노드와 연결된 자식 노드, dist: 노드와 노드 사이의 거리
int N, node, child, dist;
// 트리를 입력받은 뒤
cin >> N;
while (N--) {
cin >> node >> child;
while (child != -1) {
cin >> dist;
tree[node].push_back({child, dist});
cin >> child;
}
}
// 임의의 노드로부터 가장 거리가 먼 노드를 구하고
dfs(1, 0, 0);
// 그 노드로부터 가장 거리가 먼 노드와의 거리를 구해 출력한다
dfs(ans._node, ans._node, 0);
printf("%d\n", ans._dist);
return 0;
}
2. 트리에서 루트 노드와 리프 노드까지의 거리를 반지름이라 하면, 이 문제에서 구하고자 하는 답은 가장 긴 두 반지름의 합이다. 이 반지름은 루트의 자식 노드를 루트 노드로 갖는 서브 트리의 반지름과 루트 노드에서 자식 노드까지의 거리의 합으로 구할 수 있으므로, dfs를 이용해 구현 가능하다.
#include <iostream>
#include <vector>
using namespace std;
typedef pair<int, int> edge;
#define MAX 100000
#define _node first
#define _dist second
// 트리의 최대 지름
int ans = 0;
// tree[i]: 노드 i와 연결된 에지(들)
vector<edge> tree[MAX + 1];
void swap(int &a, int &b) { int temp = a; a = b; b = temp; }
void set_max(int &a, int b) { a = a > b ? a : b; }
int dfs(int node, int parent) {
// node의 자식 노드를 루트로 삼는 서브 트리의 반지름 중 가장 긴 두 반지름
int dist[2] = { 0, 0 };
// node의 자식 노드에 대해
for (edge e : tree[node]) if (e._node != parent) {
// 각 서브 트리의 가장 긴 반지름을
// 현재 트리의 두 번째로 긴 반지름과 비교하여 갱신
set_max(dist[1], dfs(e._node, node) + e._dist);
// 가장 긴 두 반지름을 비교하여 정렬
if (dist[0] < dist[1]) swap(dist[0], dist[1]);
}
// 트리의 지름을 두 반지름의 합과 비교하여 갱신
set_max(ans, dist[0] + dist[1]);
// 가장 긴 반지름을 반환
return dist[0];
}
int main() {
// 입출력 속도 향상
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int N, node, child, dist;
// 트리를 입력받는다
cin >> N;
while (N--) {
cin >> node >> child;
while (child != -1) {
cin >> dist;
tree[node].push_back({child, dist});
cin >> child;
}
}
// 트리의 지름 계산
dfs(1, 0);
// 계산한 트리의 지름을 출력한다
cout << ans << '\n';
return 0;
}
#include <iostream>
#include <vector>
using namespace std;
typedef pair<int, int> edge;
#define MAX 100000
#define _node first
#define _dist second
// 트리의 최대 지름
int ans = 0;
// tree[i]: 노드 i와 연결된 에지(들)
vector<edge> tree[MAX + 1];
void swap(int &a, int &b) { int temp = a; a = b; b = temp; }
void set_max(int &a, int b) { a = a > b ? a : b; }
int dfs(int node, int parent) {
// node의 자식 노드를 루트로 삼는 서브 트리의 반지름 중 가장 긴 두 반지름
int dist[2] = { 0, 0 };
// node의 자식 노드에 대해
for (edge e : tree[node]) if (e._node != parent) {
// 각 서브 트리의 가장 긴 반지름을
// 현재 트리의 두 번째로 긴 반지름과 비교하여 갱신
set_max(dist[1], dfs(e._node, node) + e._dist);
// 가장 긴 두 반지름을 비교하여 정렬
if (dist[0] < dist[1]) swap(dist[0], dist[1]);
}
// 트리의 지름을 두 반지름의 합과 비교하여 갱신
set_max(ans, dist[0] + dist[1]);
// 가장 긴 반지름을 반환
return dist[0];
}
int main() {
// 입출력 속도 향상
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int N, node, child, dist;
// 트리를 입력받는다
cin >> N;
while (N--) {
cin >> node >> child;
while (child != -1) {
cin >> dist;
tree[node].push_back({child, dist});
cin >> child;
}
}
// 트리의 지름 계산
dfs(1, 0);
// 계산한 트리의 지름을 출력한다
cout << ans << '\n';
return 0;
}