-
[알고리즘] 최소신장트리 구하기 - 크루스칼 알고리즘 C++IT&컴퓨터공학/자료구조&알고리즘 2021. 2. 14. 22:09
앞에서 최소신장트리를 구하는 두가지 알고리즘을 살펴봤다.
두개 중 먼저 크루스칼 알고리즘을 구현해보려 한다.
크루스칼 알고리즘
크루스칼 알고리즘은 간선의 cost 를 오름차순으로 정렬하고 제일 cost가 싼 간선 순서대로 연결시키는 알고리즘이다.
이때 사이클이 만들어지면 안되므로, 간선 추가 시 사이클이 발생하는지를 판단하는 알고리즘이 따로 필요한데,
이는 Union Find 를 이용하면 된다
Union Find
총 1 부터 10까지 10개의 노드가 존재한다.
노드는 서로 연결되어 있는데,
1-2-3-4
5-6-7-8
9-10
총 3 그룹으로 나눌 수 있다.
여기서 우리는 Parent[] 라는 배열을 사용하는데, 윗칸은 노드의 번호 , 아래칸은 해당 노드의 부모 노드를 의미한다.
연결정보를 갱신하는데, 이때 작은 값을 기준으로 갱신한다.
위 그림에서 1 과 2가 서로 연결되어있으므로
노드'2' 의 부모 노드를 1로 바꾸는 식이다.
1-2-3-4 는 모두 한 그룹에 속해있지만 현재는 3과 4의 부모노드 값은 1이 아닌 걸 볼 수 있다.
3은 2와 연결되어있다 → 2는 1과 연결되어있다 → 따라서 3과 1은 연결되어있다.
그러므로 노드'3' 의 부모노드도 1로 바꿔줘야하는데, 이는 재귀를 통해 해결할 수 있다.
크루스칼 알고리즘 구현
#include <iostream> #include <vector> #include <algorithm> using namespace std; int parent[7]; class Edge { public: int node[2]; int cost; Edge(int a, int b, int cost) { this->node[0] = a; this->node[1] = b; this->cost = cost; } //간선을 오름차순으로 정렬할때 기준을 cost로 정함. bool operator<(Edge &edge) { return this->cost < edge.cost; } }; //재귀로 구현한 부모노드 가져오는 함수 int getParent(int node) { if (parent[node] == node) return node; else return getParent(parent[node]); } // 노드끼리 연결시키는 함수. 이때 부모노드는 작은 노드로 쓴다. void unionParent(int node1, int node2) { node1 = getParent(node1); node2 = getParent(node2); if (node1 < node2) parent[node2] = node1; else parent[node1] = node2; } // 사이클인지 판단하는 함수 bool isCycle(int node1, int node2) { node1 = getParent(node1); node2 = getParent(node2); if (node1 == node2) return true; else return false; } int main() { //두 노드를 연결할 간선을 정해줍니다. vector<Edge> v; v.push_back(Edge(1, 7, 12)); v.push_back(Edge(1, 4, 23)); v.push_back(Edge(1, 2, 26)); v.push_back(Edge(2, 3, 36)); v.push_back(Edge(2, 4, 21)); v.push_back(Edge(2, 5, 45)); v.push_back(Edge(3, 5, 29)); v.push_back(Edge(3, 6, 37)); v.push_back(Edge(3, 7, 55)); v.push_back(Edge(4, 7, 20)); v.push_back(Edge(5, 6, 30)); //간선을 오름차순으로 정렬합니다. sort(v.begin(), v.end()); //각 노드는 자기자신이 부모로 초기화해줍니다. for (int i = 1; i <= 7; ++i) { parent[i] = i; } int sum = 0; for (int i = 0; i < v.size(); i++) { //싸이클이 존재하지 않으면 비용을 더합니다. if (isCycle(v[i].node[0], v[i].node[1])==false) { sum += v[i].cost; unionParent(v[i].node[0], v[i].node[1]); } } cout << sum << endl; return 0; }
'IT&컴퓨터공학 > 자료구조&알고리즘' 카테고리의 다른 글
[알고리즘] Level3 ) 섬 연결하기 - C++ (0) 2021.02.14 [알고리즘] 최소 신장 트리 (0) 2021.02.14 [알고리즘] Level 3) 삼각달팽이 - C++ (0) 2021.01.26 [알고리즘]Level2 ) [3차]파일명 정렬 - C++ (0) 2021.01.17 [알고리즘] C++ STL ) sort 와 stable_sort 의 차이 (0) 2021.01.17 댓글