문제 출처
1. 문제설명
- 그래프가 주어졌을 때, 그 그래프의 최소 스패닝 트리를 구하라
- 주어진 그래프의 모든 정점들을 연결하는 부분 그래프 중에서 그 가중치의 합이 최소인 트리
- 문제 분류
- Graph, MST(Minimum Spanning Tree)
2. 알고리즘 설계
- MST 기본 문제이다.
- 크게 크루스칼 또는 프림 알고리즘이 있는데, 이 문제에서는 크루스칼을 채택했다.
- 크루스칼은 간선이 같은 그룹인지 아닌지가 초점인 알고리즘이다.
- 참고로 크루스칼을 효율적으로 구현하기 위해서는 union-find 알고리즘을 알아야 한다.
- a, b라는 두 노드를 연결한 간선이 있다고 해보자.
- 만약 a, b의 부모 노드가 둘다 c라면 a와 b를 잇는 간선을 연결하면 사이클이 생겨버린다.
- union-find
- 크루스칼은 비용이 적은 간선을 찾는 그리디이기 때문에 간선 비용이 적은 순으로 정렬해둔다.
- 모든 노드에 대한 부모 노드를 자기 자신으로 초기화한다.
- 만약 두 부모 노드가 같지 않다면(초기에는 자기 자신이다.) 둘 중 하나의 노드 이름으로 부모명을 정한다.
A->B
라면 A가 부모가 되는 식으로 구현했다.
- 두 부모 노드가 같다면, 사이클이 형성되므로 건너뛴다.
3. 전체 코드
#include <bits/stdc++.h>
using namespace std;
int V, E, a, b, c, P[10'002], ans;
tuple<int,int,int> edge[1'000'002];
int find(int x) {
if(P[x] == x) return x;
else return P[x] = find(P[x]);
}
void uni(int f, int t) {
f = find(f);
t = find(t);
P[t] = f;
}
int main(void) {
ios::sync_with_stdio(false);
cin.tie(NULL);
cin >> V >> E;
for(int i=0; i<E; i++){
cin >> a >> b >> c;
edge[i] = {c, a, b};
}
sort(edge, edge+E);
for(int i=1; i<=V; i++) P[i] = i;
for(int i=0; i<E; i++) {
int f, t, cost;
tie(cost, f, t) = edge[i];
if(find(f) != find(t)) {
uni(f, t);
ans += cost;
}
}
cout << ans;
return 0;
}