크루스칼 알고리즘
가능한 한 최소한의 비용으로 신장 트리를 찾는 것
1. 간선 데이터를 비용에 따라 오름차순 정렬
2. 간선을 하나씩 확인하며 현재의 간선이 사이클을 발생시키는지 확인
- 사이클이 발생하지 않는. 경우 최소 신장 트리에 포함
- 사이클이 발생하는 경우 최소 신장 트리에 포함시키지 않음.
3. 모든 간선에 대하여 2번의 과정 반복
package java_0626_크루스칼;
import java.util.*;
class Edge implements Comparable<Edge> {
private int distance; // 비용
private int nodeA; // 시작점
private int nodeB; // 종료점
public Edge(int distance, int nodeA, int nodeB) {
this.distance = distance;
this.nodeA = nodeA;
this.nodeB = nodeB;
}
public int getDistance() {
return this.distance;
}
public int getNodeA() {
return this.nodeA;
}
public int getNodeB() {
return this.nodeB;
}
// 거리(비용)가 짧은 것이 높은 우선순위를 가지도록 설정
@Override
public int compareTo(Edge other) {
return Integer.compare(this.distance, other.distance);
}
}
public class Main {
public static int max;
// 노드의 개수(V)와 간선(Union 연산)의 개수(E)
// 노드의 개수는 최대 100,000개라고 가정
public static int v, e;
public static int[] parent = new int[1000001]; // 부모 테이블 초기화하기
// 모든 간선을 담을 리스트와, 최종 비용을 담을 변수
public static ArrayList<Edge> edges = new ArrayList<>();
public static int result = 0;
// 특정 원소가 속한 집합을 찾기
public static int findParent(int x) {
// 루트 노드가 아니라면, 루트 노드를 찾을 때까지 재귀적으로 호출
if (x == parent[x]) return x;
return parent[x] = findParent(parent[x]);
}
// 두 원소가 속한 집합을 합치기
public static void unionParent(int a, int b) {
a = findParent(a);
b = findParent(b);
if (a < b) parent[b] = a;
else parent[a] = b;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
v = sc.nextInt();
e = sc.nextInt();
// 부모 테이블상에서, 부모를 자기 자신으로 초기화
for (int i = 1; i <= v; i++) {
parent[i] = i;
}
// 모든 간선에 대한 정보를 입력 받기
for (int i = 0; i < e; i++) {
int a = sc.nextInt();
int b = sc.nextInt();
int cost = sc.nextInt();
edges.add(new Edge(cost, a, b));
}
// 간선을 비용순으로 정렬
Collections.sort(edges);
// 간선을 하나씩 확인하며
for (int i = 0; i < edges.size(); i++) {
int cost = edges.get(i).getDistance();
int a = edges.get(i).getNodeA();
int b = edges.get(i).getNodeB();
// 사이클이 발생하지 않는 경우에만 집합에 포함
if (findParent(a) != findParent(b)) {
unionParent(a, b);
result += cost;
if (cost > max) max = cost;
}
}
System.out.println(result - max);
}
}
핵심 아이디어 (전체 그래프에서 2개의 최소 신장 트리를 만들어야 함)
크루스칼 알고리즘으로 최소 신장 트리를 찾은 뒤에 최소 신장 트리를 구성하는 간선 중 가장 비용이 큰 간선을 제거
1. 최소 신장 트리 구축
2. 최소 신장 트리의 간선 중 가장 비용이 큰 간선 제거
사이클이 발생하지 않는 경우(a, b가 같은 집합이 아닌 경우) 유니온 연산 실행(같은 집합으로 만드는 과정)
'코테 > 백준' 카테고리의 다른 글
백준 2018번: 수들의 합 5 - Java (0) | 2024.06.26 |
---|---|
백준 9372번: 상근이의 여행 - Java (0) | 2024.06.26 |
백준 1717번: 집합의 표현 - Java (0) | 2024.06.26 |
백준 1541 잃어버린 괄호 - 파이썬 (0) | 2024.06.25 |
백준 10816 숫자 카드 2 - 파이썬 (0) | 2024.06.25 |