main
):입력 처리:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine(), " ");
V = Integer.parseInt(st.nextToken());
int E = Integer.parseInt(st.nextToken());
BufferedReader
와 StringTokenizer
를 사용하여 사용자로부터 정점(V)과 간선(E)의 개수를 입력받습니다. V
는 정점의 수, E
는 간선의 수를 의미합니다.초기화 및 입력된 위치 저장:
Edge[] edges = new Edge[E];
for (int i = 0; i < E; i++) {
st = new StringTokenizer(br.readLine(), " ");
edges[i] = new Edge(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
}
Edge
객체 배열을 생성하여 입력받은 간선 정보를 저장합니다. 각 간선은 시작 정점(start
), 끝 정점(end
), 그리고 가중치(weight
)로 구성됩니다.Kruskal 알고리즘을 통한 최소 신장 트리(MST) 탐색:
Arrays.sort(edges); // 간선의 가중치 기준 오름차순 정렬
make(); // 단위 서로소 집합(트리) 생성, 모든 정점을 각각의 집합으로 초기화
int cnt = 0, cost = 0;
for (Edge edge : edges) {
if (union(edge.start, edge.end)) { // 두 정점이 같은 집합에 속하지 않는 경우에만 union 수행
cost += edge.weight; // MST의 총 비용에 현재 간선의 가중치 추가
if (++cnt == V - 1) break; // MST가 완성된 경우 루프 종료
}
}
union
연산을 통해 간선을 선택하며, 이 과정에서 cnt
변수가 V-1
에 도달하면 최소 신장 트리가 완성되었다는 의미로 반복문을 종료합니다.결과 출력:
System.out.println(cost);
make
, findSet
, union
):(a) make
함수:
초기화:
parents = new int[V];
for (int i = 0; i < V; i++) parents[i] = -1; // 각 정점을 자기 자신을 대표로 하는 집합으로 초기화
parents
배열을 초기화하여 각 정점이 자기 자신을 대표로 가지는 단위 집합으로 설정합니다. -1
은 해당 정점이 자기 자신을 루트로 가지며, 집합 크기가 1임을 의미합니다.(b) findSet
함수:
탐색:
if (parents[a] < 0) return a; // 루트 노드를 찾았을 경우 루트를 반환
return parents[a] = findSet(parents[a]); // 경로 압축을 통해 루트 노드로 바로 연결
(c) union
함수:
탐색:
int firstRoot = findSet(first);
int secondRoot = findSet(second);
if (firstRoot == secondRoot) return false; // 두 정점이 이미 같은 집합에 속해 있는 경우 false 반환
false
를 반환하여 해당 간선을 추가하지 않습니다.결과 업데이트:
parents[firstRoot] += parents[secondRoot]; // 집합 크기를 업데이트 (절대값 사용)
parents[secondRoot] = firstRoot; // 두 번째 트리를 첫 번째 트리에 연결
return true;
parents
의 절대값)를 관리하여 효율적인 병합이 이루어지도록 합니다. 최종적으로 true
를 반환하여 간선이 추가되었음을 나타냅니다.package MST.Kruskal;
import java.io.*;
import java.util.*;
public class MST_KruskalTest {
static int V;
static int[] parents;
static void make() {
parents = new int[V];
for (int i = 0; i < V; i++) parents[i] = -1; // Arrays.fill(parents, -1); 로 대체 가능
}
static int findSet(int a) {
if (parents[a] < 0) return a;
return parents[a] = findSet(parents[a]); // 집합 대표 -> 자신의 부모로 변경
}
static boolean union(int first, int second) {
int firstRoot = findSet(first);
int secondRoot = findSet(second);
if (firstRoot == secondRoot) return false;
// 집합 크기에 따라 위치 조정하도록 처리도 가능
// 현재 편의상 첫 번째 트리에 두 번째 트리를 붙임
parents[firstRoot] += parents[secondRoot]; // 집합 크기 관리 (절대값 사용)
parents[secondRoot] = firstRoot;
return true;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine(), " ");
V = Integer.parseInt(st.nextToken());
int E = Integer.parseInt(st.nextToken());
Edge[] edges = new Edge[E];
for (int i = 0; i < E; i++) {
st = new StringTokenizer(br.readLine(), " ");
edges[i] = new Edge(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
}
// Kruskal 시작
Arrays.sort(edges); // 간선의 가중치 기준 오름차순
make(); // 단위 서로소 집합(트리) 생성, 모든 집합 -> 분리 집합
int cnt = 0, cost = 0;
for (Edge edge : edges) {
if (union(edge.start, edge.end)) {
cost += edge.weight;
if (++cnt == V - 1) break; // 최소 신장 트리 완성
}
}
System.out.println(cost);
}
static class Edge implements Comparable<Edge> {
int start;
int end;
int weight;
public Edge(int start, int end, int weight) {
super();
this.start = start;
this.end = end;
this.weight = weight;
}
@Override
public int compareTo(Edge o) {
return Integer.compare(this.weight, o.weight);
}
}
}