티스토리 뷰

Algorithm/BOJ

[백준 7812] 중앙 트리

giiro 2021. 6. 21. 01:43

문제

https://www.acmicpc.net/problem/7812

 

7812번: 중앙 트리

입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스의 첫 줄에는 트리의 정점의 수 n이 주어진다. (1 ≤ n ≤ 10,000) 각 정점은 0번부터 n-1번까지 번호가 붙여져 있다. 다음 n-1개 줄

www.acmicpc.net

 

풀이

1. 0번부터 n - 1번까지 중앙 정점을 옮겨가며 매번 거리를 계산하는게 아니라 0번 정점과 그 외 정점사이의 거리를 구한 후, 중앙 정점을 옮길 때마다 추가/감소되는 비용만 구하면 최소거리인 중앙정점을 구할 수 있습니다.

 

2. 정점을 옮길 때마다 추가/감소되는 비용은 정점과 연결된 간선들의 개수와 관련이 있고, 이는 dfs를 돌려 연결된 간선개수를 찾을 수 있습니다.

 

3.  (u, v)가 cost = c 로 연결되어있고, 중앙 정점을 u번 -> v번 정점으로 옮길 때 드는 비용은 아래와 같습니다.

  (추가되는 비용) = (모든 간선의 개수 - (v에 연결된 간선들의 개수 - 1)) * c = (n - 1 - (sz[v] - 1)) * c

  (감소되는 비용) = (v에 연결된 간선들의 개수) * c  = (-sz[v]) * c

  ∴ (추가되는 비용 + 감소되는 비용) = (n - 2 * sz[v]) * c

 

코드

#include <bits/stdc++.h>
using namespace std;

typedef pair<int, int> pii;
typedef long long ll;

int n, a, b, w, sz[10001];
ll mn, sum;
vector<pii> adj[10001];

void dfs(int u, int p, int s){
	sz[u]= 1;
	for (auto [v,c] : adj[u]){
		if (v == p) continue;
		dfs(v, u, s + c);
		sum += s + c;
		sz[u] += sz[v];
	}
}

void solve(int u, int p, ll co){
	mn = min(mn, co);
	for (auto [v,c] : adj[u]){
		if (v == p) continue;
		solve(v, u, co + (n - 2 * sz[v]) * c);
	}
}

int main() {
	cin.tie(NULL); cout.tie(NULL);
	ios_base::sync_with_stdio(false);

	while (1){
		cin >> n;
		if (!n) break;

		memset(sz, 0, sizeof(sz));
		for (int i = 0 ; i < n; i++) adj[i].clear();
		mn = 0x3f3f3f3f3f3f3f3f, sum = 0;
		
		for (int i = 0 ; i < n - 1; i++){
			cin >> a >> b >> w;
			adj[a].push_back({b,w});
			adj[b].push_back({a,w});
		}
		
		dfs(0, -1, 0); // 1. find size
		solve(0, -1, sum); // 2. find ans
		cout << mn << "\n";
	}
}

 

 

 

'Algorithm > BOJ' 카테고리의 다른 글

[백준 13018] 특이한 수열  (0) 2021.07.02
[백준 16566] 카드 게임  (0) 2021.03.17
[백준 7045] Tree Cutting  (0) 2021.03.17
[백준 5867] Scrambled Letters  (0) 2021.02.07
[백준 20438] 출석체크  (0) 2021.01.08
댓글