티스토리 뷰
문제
7812번: 중앙 트리
입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스의 첫 줄에는 트리의 정점의 수 n이 주어진다. (1 ≤ n ≤ 10,000) 각 정점은 0번부터 n-1번까지 번호가 붙여져 있다. 다음 n-1개 줄
www.acmicpc.net
풀이
트리DP를 사용합니다.
먼저, 예제에서 나온 트리를 보겠습니다.

위 트리의 \(A\)노드에서 다른 모든 노드들로 이동할 때, 각 간선이 이용되는 횟수는 다음과 같습니다.

\(A\)를 루트로 하여 트리를 순회하면서 각 \((B, C, D, E)\)를 루트로 하는 서브 트리의 크기(노드의 개수, 즉, 루트라고 하는 노드와 그 노드의 부모와 이어지는 간선이 이용되는 횟수)에 그 간선의 가중치를 곱한 다음 그들의 합을 구하면 A가 중앙 정점일 때의 합을 구할 수 있습니다.
\((A\)의 경우\(: 2 \cdot 4 + 1 \cdot 1 + 2 \cdot 7 + 5 \cdot 1 = 28)\)
모든 노드마다 위의 방법을 이용해서 구하면 시간이 오래 걸릴 수 있기에 더 간단하고 빠른 방법을 사용해보겠습니다.
\(A\)의 자식 노드인 \(B\)를 루트로 할 경우는 다음과 같습니다.

그림을 보면 \(A\)와 \(B\)를 이으는 간선 말고는 모두 이용되는 횟수가 같습니다. 즉, 트리를 순회하면서 다음 노드의 가중치의 합을 구할 때는 전 노드의 가중치의 합에서 전 노드와 이어지는 간선의 가중치와 다음 노드의 서브 트리의 크기의 곱을 뺀 다음, 다음 노드의 서브 트리에 포함되지 않는 노드의 개수, 즉, 전체 노드의 개수에서 다음 노드의 서브 트리의 크기를 뺀 값에 간선의 가중치를 곱한 것을 더해주면 다음 노드의 가중치의 합이 됩니다.
\((B\)의 경우\(: 28 - 2 \cdot 4 + 2 \cdot 1 = 22)\)
이렇게 구한 값들 중 최솟값이 답이 됩니다.
코드
#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> p;
int N;
ll mn;
vector<ll> cnt, sum;
vector<vector<p>> graph;
void get_tree(int cur, int pnode) {
cnt[cur] = 1;
for (int i = 0; i < graph[cur].size(); ++i) {
if (graph[cur][i].x == pnode) continue;
int next = graph[cur][i].x;
int cost = graph[cur][i].y;
get_tree(next, cur);
cnt[cur] += cnt[next];
sum[cur] += cnt[next] * cost + sum[next];
}
}
void get_sum(int cur, int pnode) {
for (int i = 0; i < graph[cur].size(); ++i) {
if (graph[cur][i].x == pnode) continue;
int next = graph[cur][i].x;
int cost = graph[cur][i].y;
ll csum = sum[cur];
csum -= cost * cnt[next];
csum += (N - cnt[next]) * cost;
sum[next] = csum;
get_sum(next, cur);
}
mn = min(mn, sum[cur]);
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
while (1) {
cin >> N;
if (N == 0) break;
graph.clear();
graph.resize(N);
cnt.clear();
sum.clear();
cnt = sum = vector<ll>(N);
mn = 1e18;
for (int i = 0; i < N - 1; ++i) {
int a, b, c;
cin >> a >> b >> c;
graph[a].push_back({b, c});
graph[b].push_back({a, c});
}
get_tree(0, 0);
get_sum(0, 0);
cout << mn << "\n";
}
return 0;
}'BOJ' 카테고리의 다른 글
| [BOJ 15669] 나무 위의 입자 (0) | 2021.05.13 |
|---|---|
| [BOJ 1693] 트리 색칠하기 (0) | 2021.05.13 |
| [BOJ 1761] 정점들의 거리 (0) | 2021.05.12 |
| [BOJ 3584] 가장 가까운 공통 조상 (0) | 2021.05.08 |
| [BOJ 1949] 우수 마을 (0) | 2021.05.05 |
- Total
- Today
- Yesterday
- Tree DP
- graph
- Tree
- knapsack
- Combinatorics
- 737-2
- binary search
- Union Find
- DP Traceback
- sorting
- codeforces
- PBA
- Prefix Sum
- hello
- BOJ
- Dijkstra
- Bit Masking
- Coordinate Compression
- Sliding Window
- Greedy
- LCA
- Priority Queue
- DP
- Constructive
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |