[java] 섬 연결하기 알고리즘

섬 연결하기 알고리즘은 그래프 이론에서 사용되는 알고리즘 중의 하나입니다. 이 알고리즘은 그래프에서 모든 정점을 최소 비용으로 연결하는 최소 비용 신장 트리(Minimum Cost Spanning Tree)를 구하는 문제를 해결합니다.

Kruskal 알고리즘

Kruskal 알고리즘은 섬 연결하기 문제를 해결하는 아주 효율적인 알고리즘 중의 하나입니다. 이 알고리즘은 그리디 알고리즘의 한 예로, 간선을 가중치 순으로 정렬한 뒤, 순서대로 선택하여 신장 트리를 형성하는 방식으로 동작합니다.

Kruskal 알고리즘의 동작 과정은 다음과 같습니다.

  1. 그래프의 간선을 가중치 순으로 정렬합니다.
  2. 가중치가 가장 작은 간선부터 선택하여 현재 신장 트리에 추가합니다. 이때 간선이 추가되었을 때 신장 트리에 사이클이 형성되지 않는다면 해당 간선을 선택합니다.
  3. 모든 정점이 포함될 때까지 2번의 과정을 반복합니다.

Kruskal 알고리즘을 Java로 구현한 예시 코드는 다음과 같습니다.

import java.util.*;

class Edge implements Comparable<Edge> {
    int src, dest, weight;
    
    public int compareTo(Edge compareEdge) {
        return this.weight - compareEdge.weight;
    }
}

class Graph {
    int V, E;
    Edge[] edges;
    
    Graph(int V, int E) {
        this.V = V;
        this.E = E;
        edges = new Edge[E];
        for (int i = 0; i < E; i++) {
            edges[i] = new Edge();
        }
    }
    
    int find(int[] parent, int i) {
        if (parent[i] == -1)
            return i;
        return find(parent, parent[i]);
    }
    
    void union(int[] parent, int x, int y) {
        int xset = find(parent, x);
        int yset = find(parent, y);
        parent[xset] = yset;
    }
    
    void kruskalMST() {
        Edge[] result = new Edge[V];
        int e = 0;
        int i = 0;
        for (i = 0; i < V; i++) {
            result[i] = new Edge();
        }
        
        Arrays.sort(edges);
        
        int[] parent = new int[V];
        Arrays.fill(parent, -1);
        
        i = 0;
        while (e < V - 1) {
            Edge next_edge = edges[i++];
            
            int x = find(parent, next_edge.src);
            int y = find(parent, next_edge.dest);
            
            if (x != y) {
                result[e++] = next_edge;
                union(parent, x, y);
            }
        }
        
        System.out.println("Edge \tWeight");
        for (i = 0; i < e; i++) {
            System.out.println(result[i].src + " - " + result[i].dest + "\t" + result[i].weight);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        int V = 4; // 정점의 수
        int E = 5; // 간선의 수
        
        Graph graph = new Graph(V, E);
        
        graph.edges[0].src = 0;
        graph.edges[0].dest = 1;
        graph.edges[0].weight = 10;
        
        graph.edges[1].src = 0;
        graph.edges[1].dest = 2;
        graph.edges[1].weight = 6;
        
        graph.edges[2].src = 0;
        graph.edges[2].dest = 3;
        graph.edges[2].weight = 5;
        
        graph.edges[3].src = 1;
        graph.edges[3].dest = 3;
        graph.edges[3].weight = 15;
        
        graph.edges[4].src = 2;
        graph.edges[4].dest = 3;
        graph.edges[4].weight = 4;
        
        graph.kruskalMST();
    }
}

위의 예시 코드는 4개의 정점과 5개의 간선을 가지는 그래프에서 Kruskal 알고리즘을 이용하여 최소 비용 신장 트리를 구하는 예시입니다. 출력 결과는 다음과 같습니다.

Edge    Weight
2 - 3    4
0 - 3    5
0 - 1    10

추가로, Kruskal 알고리즘의 시간 복잡도는 O(ElogV)입니다.

참고 자료