문제
- 문제 링크
BOJ 26159 - 트리와 수열
$N$개의 정점으로 이루어진 트리와 $N - 1$개의 수열이 주어진다.
간선에 수열의 원소들을 하나씩 대응시켜 가중치를 매길 때, $min(Σdist(i, j))$ $mod$ $1000000007$ 의 값을 구해보자.
TL : $2$ sec, ML : $512$ MB
$2 ≤ N ≤ 100,000$ $1 ≤ a_i ≤ 10^9$
알고리즘 분류
- 그래프 이론(graphs)
- 그래프 탐색(graph_traversal)
- 트리(trees)
- 다이나믹 프로그래밍(dp)
- 트리에서의 다이나믹 프로그래밍(dp_tree)
- 그리디 알고리즘(greedy)
- 정렬(sorting)
풀이
척 보면 드는 생각이, "가장 인기 없는 간선일수록 큰 가중치를 부여 하는 것이 이득이지 않을까?" 였다.
많이 이용되는 간선일수록 최대한 적은 가중치를 메기는 것이 최선일테니 말이다.
이를 위해선 존재하는 모든 $(i, j)$쌍에 대해 각 간선마다 이용되는 횟수를 계산해야 한다.
구체적으로 $dp[i] :$ " 정점 $i$와 $i$의 부모를 잇는 간선이 이용되는 횟수" 라고 할 때,
$($정점 $i$를 루트로 하는 서브 트리의 크기$)$ $*$ $($이에 속하지 않는 나머지 모든 정점$)$ 의 형태로 구할 수 있다.
이제 수열 $a[]$ 와 $dp[]$ 가 서로 다른 성격(단조 증가 / 감소)을 갖도록 정렬하면 $Σdist(i, j)$ $mod$ $1000000007$ 의 최솟값을 계산할 수 있다.
증명은 여기 에서 간단하게 확인할 수 있다.
자세한 흐름은 코드를 참조하자.
전체 코드
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 32 33 34 35 36 37 38 39 40 | #include<bits/stdc++.h> #define N 100001 using namespace std; vector <int> Gr[N]; long long dp[N]; int n, a[N]; int SubSize(int p) { dp[p] = 1; for (int i : Gr[p]) if (!dp[i]) dp[p] += SubSize(i); return dp[p]; } void Init() { ios_base::sync_with_stdio(0); cin.tie(0); cin >> n; for (int i, j, o{}; ++o < n;) cin >> i >> j, Gr[i].push_back(j), Gr[j].push_back(i); for (int i(1); i < n; cin >> a[i++]); } void Solve(int r = 0) { SubSize(1); sort(a, a + n); for (int i(1); i <= n; i++) dp[i] *= (n - dp[i]); sort(dp + 1, dp + n + 1, greater<>()); for (int i(1); i < n; i++) r = (r + dp[i] * a[i]) % 1000000007; cout << r; } int main() { Init(); Solve(); } | cs |
comment
끝
'Problem Solving > Baekjoon Online Judge (Gold)' 카테고리의 다른 글
백준 27892 - 특별한 큰 분수 (C++) (0) | 2023.05.22 |
---|---|
백준 21695 - Школа танцев (C++) (0) | 2023.05.20 |
백준 25498 - 핸들 뭘로 하지 (C++) (1) | 2023.05.12 |
백준 1623 - 신년 파티 (C++) (0) | 2023.05.10 |
백준 26077 - 서커스 나이트 (C++) (0) | 2023.05.09 |