import static algo.UnionFind.*;
import java.util.Arrays;
import java.util.Comparator;
import java.util.stream.IntStream;
/**
* edges = 간선 정보로 {1,2,5} 는 1 -> 2로 5의 가중치를 의미
* v = 정점의 개수
* e = 간선의 개수
*
* 여기서 UnionFind는 제가 직접 만들어둔 UnionFind를 사용했습니다. 관련 게시글이 블로그에 있으니 참고하세요.
*/
public class Kruskal {
// 최소 비용 구하기
public static int kruskal(int[][] edges, int v, int e) {
int weightSum = 0;
// 1. 간선들의 가중치를 오름차순으로 정렬
Arrays.sort(edges, Comparator.comparing(edge -> edge[2]));
// union-find를 사용하기 위한 배열 생성
int[] parents = IntStream.range(0, v + 1).toArray();
// 2. 간선을 순서대로 선택
for (int i = 0; i < e; i++) {
// 사이클이 없을 때만
if (find(parents, edges[i][0]) != find(parents, edges[i][1])) {
union(parents, edges[i][0], edges[i][1]);
// 가중치 합산
weightSum += edges[i][2];
}
}
return weightSum;
}
}
프림
프림은 우선순위큐로 구현하므로, 자바에서 제공하는 PriortiyQueue를 이용했습니다.
import java.util.ArrayList;
import java.util.Comparator;
import java.util.PriorityQueue;
public class Prim {
public static int prim(int[][] edges, int v, int e) {
int weightSum = 0;
// 간선 정보를 그래프로 만들어 주는 밑작업
ArrayList<ArrayList<Node>> graph = new ArrayList<>();
for (int i = 0; i < v + 1; i++) {
graph.add(new ArrayList<>());
}
for (int i = 0; i < e; i++) {
ArrayList<Node> nodeA = graph.get(edges[i][0]);
ArrayList<Node> nodeB = graph.get(edges[i][1]);
nodeA.add(new Node(edges[i][1], edges[i][2]));
nodeB.add(new Node(edges[i][0], edges[i][2]));
}
// 노드에 방문했는지 체크할 배열 생성
boolean[] visited = new boolean[v + 1];
// 노드들의 간선 중 가중치가 가장 작은 간선을 선택하기 위한 우선순위 큐
PriorityQueue<Node> pq = new PriorityQueue<>(Comparator.comparing(edge -> edge.weight));
// 1번 노드부터 시작
pq.add(new Node(1, 0));
// MST 간선 수 체크
int cnt = 0;
while (!pq.isEmpty()) {
// 현재 노드
Node cur = pq.poll();
cnt += 1;
// 현재 노드가 방문한 노드라면 건너뛰기
if (visited[cur.to]) {
continue;
}
// 현재 노드 방문 처리
visited[cur.to] = true;
// 현재 노드로 올 때 발생한 가중치 더하기
weightSum += cur.weight;
// 현재 노드가 가지고 있는 인접 노드 수만큼 반복
for (int i = 0; i < graph.get(cur.to).size(); i++) {
// 인접 노드 가져오기
Node adjNode = graph.get(cur.to).get(i);
// 방문한 노드라면 건너뛰기
if (visited[adjNode.to]) {
continue;
}
// 인접 노드를 우선순위 큐에 추가
pq.offer(adjNode);
}
}
return weightSum;
}
// 이동하려는 노드를 위한 자료구조
static class Node {
int to;
int weight;
public Node(int to, int weight) {
this.to = to;
this.weight = weight;
}
}
}