https://www.acmicpc.net/problem/1197
그래프가 주어졌을 때, 그 그래프의 최소 스패닝 트리를 구하는 프로그램을 작성하시오.
최소 스패닝 트리는, 주어진 그래프의 모든 정점들을 연결하는 부분 그래프 중에서 그 가중치의 합이 최소인 트리를 말한다.
**신장 트리란?**
그래프 상에서 모든 노드가 사이클 없이 연결된 부분 그래프
사이클이 없으므로, 정점의 개수가 v개일 때 간선은 반드시 v-1개여야 한다.
최소 신장 트리 --> 신장 트리 중에서 간선의 가중치의 합이 최소인 트리
각 간선의 가중치를 고려하여 신장트리를 구성할 것들을 적절히 골라주면 된다.
for(int i = 0; i < E; i++){
int a, b, c;
if(cnt == V-1)
break;
c = v[i].first;
a = v[i].second.first;
b = v[i].second.second;
if(Find(a) == Find(b))
continue;
Union(a, b);
ans += c;
cnt++;
}
우선 사이클이 생기면 안된다는 조건은 분리집합을 이용하면 편하다.
두 정점의 대표 원소가 같다는 것은 두 정점이 이미 한번 연결되었다는 뜻이며, 이 두 정점을 서로 연결하는 간선을 추가할 경우, 사이클이 생기게 된다.

**사진과 같은 신장 트리에서 A와 B는 같은 조상을 공유하고 있기에 둘을 연결하는 간선을 그으면 사이클이 생긴다. **
그래프에 대한 정보를 가중치에 대하여 오름차순으로 정렬한다.
가중치가 작은 간선 부터 참조하여 사이클이 생기지 않는 조건 하에 그리디하게 간선들을 선택하는 것이다.
간선의 개수가 v-1개가 되는 순간에 루프를 멈추면 최소 스패닝 트리의 가중치 합을 구할 수 있다.
전체 코드
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<pair<int, pair<int, int>>> v;
vector<int> parent;
int Find(int x) {
if(parent[x] == x)
return x;
return parent[x] = Find(parent[x]);
}
void Union(int a, int b) {
a = Find(a);
b = Find(b);
parent[a] = b;
}
void Solve(int V, int E) {
int cnt = 0, ans = 0;
for(int i = 0; i <= V; i++) {
parent[i] = i;
}
for(int i = 0; i < E; i++) {
int a, b, c;
cin >> a >> b >> c;
v.push_back({c, {a, b}});
}
sort(v.begin(), v.end());
for(int i = 0; i < E; i++){
int a, b, c;
if(cnt == V-1)
break;
c = v[i].first;
a = v[i].second.first;
b = v[i].second.second;
if(Find(a) == Find(b))
continue;
Union(a, b);
ans += c;
cnt++;
}
cout << ans;
}
int main() {
int V, E;
cin >> V >> E;
parent.resize(V+1);
Solve(V, E);
}
'알고리즘' 카테고리의 다른 글
| Boj 7453 & 1450 c++ MITM 알고리즘 (0) | 2025.10.19 |
|---|---|
| Boj 2887 c++ 행성터널 (1) | 2025.10.09 |
| Boj 10775 c++ 공항 (1) | 2025.10.08 |
| Boj 9252 c++ LCS 2 (0) | 2025.10.01 |
| Boj 12852 c++ 1로 만들기 2 (0) | 2025.10.01 |