Kruskal 알고리즘이란
탐욕적인 방법(greedy method)을 이용하여 네트워크(가중치를 간선에 할당한 그래프)의 모든 정점을 최소비용으로
연결하는 최적 해답을 구하는 것
greedy method
결정을 해야할때마다 그 순간에 가장 좋다고 생각되는 것을 선택함으로써 최종적인 해답에 도달하는 것.
greedy method는 그 순간에는 최적이지만 전체적인 관점에서 최적이라는 보장이 없기 때문에 반드시
검증해야 한다.
다행히 Kruskal 알고맂므은 최적의 해답을 주는것으로 증명되어 있다.
MST(최소비용 신장트리)가 최소비용의 간선으로 구성되되고 사이클을 포함하지 않는다는 조건에 근거하여
각 다께에서 사이클을 이루지 않는 최소비용간선을 선택한다.
Kruskal 알고리즘의 동작
그래프의 간선들을 가중치의 오름차순으로 정렬한다.
정렬된 간선 리스트에서 순서대로 사이클을 형성하지 않는 간선을 선택한다.
즉, 가장 낮은 가중치를 먼저 선택한다.
사이클을 형성하는 간선을 제외한다.
해당 간선을 현재의 MST의 집합에 추가한다.
Kruskal 알고리즘의 구체적인 동작과정
Kruskal 알고리즘을 이용하여 MST를 만드는 과정
간선 선택을 기반으로 하는 알고리즘
이전 단계에서 만들어진 신장트리와는 상관없이 무조건 최소 간선만을 선택하는 방법


주의사항
다음 간선을 이미 선택된 간선들의 집합에 추가할 때 사이클을 생성하는지를 체크해야 한다.
새로운 간선이 이미 다른 경로에 의해 연결되어 있는 정점들을 연결할 때 사이클이 형성된다.
즉, 추가할 새로운 간선의 양끝 정점이 같은 집합에 속해 있으면 사이클이 형성된다.
싸이클 생성여부를 확인하는 방법
추가하고자 하는 간선의 양끝 정점이 같은 집합에 속해 있는지를 먼저 검사해야 한다.
union-find 알고리즘 사용
Kruskal 알고리즘의 시간 복잡도
union-find 알고리즘을 이용하면 Kruskal 알고리즘의 시간 복잡도는 간선들을 정렬하는 시간에 좌우된다.
즉, 간선 e개를 퀵 정렬과 같은 효율적인 알고리즘으로 정렬한다면
Kruskal알고리즘의 시간 복잡도는 O(elog₂e)이 된다.
Prim 알고리즘의 시간 복잡도는 O(n^2)이므로
그래프 내에 적은 숫자의 간선만을 가지는 희소그래프(Sparse Graph)의 경우 Kruskal 알고리즘이 적합하고
그래프에 간선이 많이 존재하는 밀집그래프(Dense Graph)의 경우는 Prim 알고리즘이 적합하다.
예제코드
import java.util.*;
public class Kruskal {
static int V, E;
static PriorityQueue<Edge> pq;
static ArrayList<Edge> MST;
static int parent[];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
V = sc.nextInt();
E = sc.nextInt();
pq = new PriorityQueue<>();
MST = new ArrayList<>();
parent = new int[V + 1];
//for init
for(int i = 0; i <= V; i++){
parent[i] = i;
}
for(int i = 1; i <= E; i++){
int u = sc.nextInt();
int v = sc.nextInt();
int val = sc.nextInt();
pq.add(new Edge(u, v, val));
}
while(MST.size() < (V - 1)){
Edge e = pq.poll();
if(find(e.begin) != find(e.end)){
MST.add(e);
union(e.begin, e.end);
}
}
for(int i = 0; i < MST.size(); i++){
System.out.println(MST.get(i).begin + " " + MST.get(i).end + " " + MST.get(i).val);
}
}
public static int find(int n){
if(n == parent[n]){
return n;
}else{
int p = find(parent[n]);
parent[n] = p;
return p;
}
}
public static void union(int n1, int n2){
int p1 = find(n1);
int p2 = find(n2);
if(p1 != p2){
parent[p1] = p2;
}
}
public static class Edge implements Comparable<Edge>{
int begin, end, val;
public Edge(int b, int e, int v){
this.begin = b;
this.end = e;
this.val = v;
}
@Override
public int compareTo(Edge o){
return this.val - o.val;
}
}
}
레퍼런스
● gmlwjd9405.github.io/2018/08/29/algorithm-kruskal-mst.html
'자료구조' 카테고리의 다른 글
세그먼트트리(구간합 트리) (0) | 2021.01.21 |
---|---|
다익스트라(Dijkstra) 알고리즘 (0) | 2021.01.20 |
프림(Prim) 알고리즘 (0) | 2021.01.19 |
최소신장트리(Minimum Spanning Tree, MST) (0) | 2021.01.19 |
해시(Hash) (0) | 2021.01.18 |