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;
}