parent 배열을 통해 판단한다. (union find 알고리즘이라고도 불린다.)parent배열은 i번째 노드의 최상위 부모(=root)를 의미한다.parent의 초기화는 parent[i] = i로 할 수 있다. (자기 자신이 부모노드가 된다는 뜻이다.)a, b간에 간선이 존재하여 이를 선택할 때, unionParent라는 함수로 두 노드가 연결됨을(즉, 집합이 됨) 표현한다. 두 노드의 값을 비교하여 번호가 작은 노드가 부모노드가 되도록 한다. 구현 메서드는 다음과 같다.void unionParent(int vertex1, int vertex2) {
vertex1 = getParent(vertex1);
vertex2 = getParent(vertex2);
if(vertex1 < vertex2) parent[vertex2] = vertex1;
else parent[vertex1] = vertex2;
}getParent함수는 vertex번호를 가진 노드의 부모 노드를 리턴한다. 이는 재귀함수로 부모노드를 타고 올라갈 수 있으며, 최상위 부모노드에 다다르면 parent[i] = i 을 만족하므로 i를 리턴하면 된다.int getParent(int vertex) {
if (parent[vertex] == vertex) return vertex;
return getParent(parent[vertex]);
}a, b의 간선을 연결하였다고 가정했을 때, 사이클이 존재한다면 a와 b의 부모노드를 구하면 같을것이다. 사이클이 존재하지 않는다면 a, b을 연결하는 간선 이외의 연결되는 간선들이 없다는 뜻이므로 a, b의 부모노드는 다를거라고 유추 가능하다.bool isCycle(int vertex1, int vertex2) {
vertex1 = getParent(vertex1);
vertex2 = getParent(vertex2);
if(vertex1 == vertex2) return true;
else return false;
}백준 1197번 문제 최소 스패닝 트리 가 최소 스패닝 트리를 구현하는 문제이다.
#include <bits/stdc++.h>
#define MAX 100001
using namespace std;
int v, e;
// weight, (start, end)
vector<pair<int, pair<int, int>>> edge;
int parent[MAX];
int getParent(int vertex) {
if (parent[vertex] = vertex) return vertex;
return getParent(parent[vertex]);
}
void unionParent(int vertex1, int vertex2) {
vertex1 = getParent(vertex1);
vertex2 = getParent(vertex2);
if(vertex1 < vertex2) parent[vertex2] = vertex1;
else parent[vertex1] = vertex2;
}
bool isCycle(int vertex1, int vertex2) {
vertex1 = getParent(vertex1);
vertex2 = getParent(vertex2);
if(vertex1 == vertex2) return true;
else return false;
}
int main() {
cin >> v >> e;
int a, b, c;
for(int i = 0; i < e; i++) {
cin >> a >> b >> c;
edge.push_back({c, {a, b}});
parent[i+1] = i+1;
}
sort(edge.begin(), edge.end());
int cnt = 0, sum = 0;
for(auto tmp : edge) {
if (cnt >= v) break;
int weight = tmp.first;
int start = tmp.second.first;
int end = tmp.second.second;
if (!isCycle(start, end)) {
unionParent(start, end);
sum += weight;
cnt++;
}
}
cout << sum;
}
vector에서 처음 원소를 가중치로 하여 가중치에 대해 오름차순으로 정렬되도록 하였다.edge를 순회하며, 선택한 간선의 개수가 노드의 개수보다 크거나 같으면 break되도록 하였다.start, end간의 사이클이 존재하지 않는다면 (!isCycle(start, end)), unionParent(start, end)로 간선을 추가하고 가중치를 더한다.pq.pop()을 하고 pop한 노드가 이미 방문했는지 체크 후, 가중치를 더한다.프림 알고리즘 또한 백준 1197번 문제 최소 스패닝 트리 로 구현하였다.
#include <bits/stdc++.h>
#define MAX 100001
using namespace std;
bool isSelected[MAX] = {0,};
vector<pair<int, int>> graph[MAX];
int v, e;
int main() {
cin >> v >> e;
int a, b, c;
for(int i = 0; i < e; i++) {
cin >> a >> b >> c;
graph[a].push_back({c, b});
graph[b].push_back({c, a});
}
int start = 1;
int cnt = 0, sum = 0;
isSelected[start] = 1;
// weight, pair<start, end>
priority_queue<pair<int, pair<int, int>>, vector<pair<int, pair<int, int>>>> pq;
for(auto tmp : graph[start]) {
pq.push({-tmp.first, {start, tmp.second}});
}
while(cnt < v - 1) {
int w = -pq.top().first;
int start = pq.top().second.first;
int end = pq.top().second.second;
pq.pop();
if(isSelected[end]) continue;
isSelected[end] = 1;
sum += w;
cnt++;
for(auto tmp : graph[end]) {
if (isSelected[tmp.second]) continue;
pq.push({-tmp.first, {end, tmp.second}});
}
}
cout << sum;
}