-> 다익스트라는 해당 노드에서 다른 모든 정점까지의 최단거리를 구하는 것, MST는 A에서 목적지 B까지 가는 가중치의 값이 가장 작은 경로를 구하는 것
즉, 다익스트라는 모든 노드의 거리, MST는 A - B까지 하나의 경로
스패닝 트리 : 모든 노드는 연결되어 있지만, 사이클이 존재하지 않는 부분 그래프를 의미.

static boolean union(int x, int y) {
int nx = find(x);
int ny = find(y);
if (nx == ny)
return false;
if (nx > ny)
parent[ny] = nx;
else
parent[nx] = ny;
return true;
}
전체 코드를 통해 크루스칼 알고리즘을 알아보자
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
//신장 트리
//n개의 정점으로 이루어진 '무향' 그래프에서 n개의 정점과 n-1개의 간선으로 이루어진 트리
//최소 신장 트리
//무향 가중치 그래프에서 신장트리를 구성하는 간선들의 가중치의 합이 최소인 신장 트리
//------------
//KRUSKAL 알고리즘 -> Union-Find O(ElogE)
//간선을 하나씩 선택해서 MST를 찾는 알고리즘
//1. 최초, 모든 간선을 가중치에 따라 '오름차순'으로 정렬
//2. 가중치가 가장 낮은 간선부터 선택하면서 트리를 증가시킴
//3. n-1개의 간선이 선택될 때까지 2를 반복
//PRIM 알고리즘 -> 우선순위 큐 or 인접행렬 O(V^2) or O(ElogV)
//1. 임의의 시작 정점 선택
//현재 트리와 연결된 간선 중 최소 비용 간선 선택
//새로운 정점을 트리에 추가
//모든 정점이 포함될 때까지 반복
public class MST_KRUSKAL {
static class Edge implements Comparable<Edge> {
int from, to, weight;
public Edge(int from, int to, int weight) {
super();
this.from = from;
this.to = to;
this.weight = weight;
}
@Override
public int compareTo(Edge o) {
// 10 - 20 : 음수 -> 뒤 값이 크다 : 그럼 그대로 위치 (교환 일어나지 않음)
// 20 - 10 : 양수 -> 앞 값이 크다 : 교환
return this.weight - o.weight; // 가중치 기준 오름차순 정렬 되도록 비교결과 리턴
// return Integer.compare(this.weight, o,weight); 간선에 음수값이 있을 수 있어서 이렇게도 가능
}
}
static Edge[] edgeList;
static int[] parent;
static int V, E;
public static void main(String[] args) throws Exception {
parent = new int[V];
for (int i = 1; i <= V; i++) {
parent[i] = i;
}
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
V = Integer.parseInt(st.nextToken());
E = Integer.parseInt(st.nextToken());
edgeList = new Edge[E];
for (int i = 0; i < E; i++) {
int from = Integer.parseInt(st.nextToken());
int to = Integer.parseInt(st.nextToken());
int weight = Integer.parseInt(st.nextToken());
edgeList[i] = new Edge(from, to, weight);
}
Arrays.sort(edgeList);
int result = 0;
int cnt = 0;
for (Edge edge : edgeList) {
if (!union(edge.from, edge.to))
continue;
result += edge.weight;
if (++cnt == V - 1)
break;
}
System.out.println(result);
}
static boolean union(int x, int y) {
int nx = find(x);
int ny = find(y);
if (nx == ny)
return false;
if (nx > ny)
parent[ny] = nx;
else
parent[nx] = ny;
return true;
}
static int find(int x) {
if (x == parent[x]) {
return x;
}
return parent[x] = find(parent[x]);
}
}
프림 알고리즘은 최소 신장트리를 구하는 또하나의 알고리즘이다. 하나의 시작 '정점'을 기준으로 가장 작은 간선과 연결된 정점을 선택하여 스패닝 트리가 될 때까지 모든 노드를 연결시킨다.
프림알고리즘은 간선의 개수가 많은 경우에는 정점 위주의 프림이 유리하다.
import java.io.*;
import java.util.*;
//신장 트리
//n개의 정점으로 이루어진 '무향' 그래프에서 n개의 정점과 n-1개의 간선으로 이루어진 트리
//최소 신장 트리
//무향 가중치 그래프에서 신장트리를 구성하는 간선들의 가중치의 합이 최소인 신장 트리
//------------
//KRUSKAL 알고리즘 -> Union-Find O(ElogE)
//간선을 하나씩 선택해서 MST를 찾는 알고리즘
//1. 최초, 모든 간선을 가중치에 따라 '오름차순'으로 정렬
//2. 가중치가 가장 낮은 간선부터 선택하면서 트리를 증가시킴
//3. n-1개의 간선이 선택될 때까지 2를 반복
//PRIM 알고리즘 -> 우선순위 큐 or 인접행렬 O(V^2) or O(ElogV)
//1. 임의의 시작 정점 선택
//현재 트리와 연결된 간선 중 최소 비용 간선 선택
//새로운 정점을 트리에 추가
//모든 정점이 포함될 때까지 반복
public class MST_PRIM {
static int TC, V, E;
static long ans;
static List<Edge>[] adjList;
static boolean[] visited;
static class Edge implements Comparable<Edge> {
int to;
long weight;
Edge(int to, long weight) {
this.to = to;
this.weight = weight;
}
@Override
public int compareTo(Edge o) {
// TODO Auto-generated method stub
return Long.compare(this.weight, o.weight);
}
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
TC = Integer.parseInt(br.readLine());
for (int k = 1; k <= TC; k++) {
StringTokenizer st = new StringTokenizer(br.readLine());
V = Integer.parseInt(st.nextToken());
E = Integer.parseInt(st.nextToken());
ans = 0;
visited = new boolean[V + 1];
adjList = new ArrayList[V + 1];
for (int i = 0; i < V + 1; i++) {
adjList[i] = new ArrayList<Edge>();
}
for (int i = 0; i < E; i++) {
st = new StringTokenizer(br.readLine());
int from = Integer.parseInt(st.nextToken());
int to = Integer.parseInt(st.nextToken());
long weight = Integer.parseInt(st.nextToken());
adjList[from].add(new Edge(to, weight));
adjList[to].add(new Edge(from, weight));
}
prim(1);
sb.append("#").append(k).append(" ").append(ans).append("\n");
}
System.out.println(sb);
}
static void prim(int start) {
PriorityQueue<Edge> pq = new PriorityQueue<>();
pq.add(new Edge(start, 0));
while (!pq.isEmpty()) {
Edge edge = pq.poll();
int to = edge.to;
long weight = edge.weight;
if (visited[to])
continue;
visited[to] = true;
ans += weight;
for (Edge e : adjList[to]) {
if (!visited[e.to]) {
pq.add(new Edge(e.to, e.weight));
}
}
}
}
}