Graph - 최소신장트리 구하기 (크루스칼 알고리즘)

ik_13038·2022년 5월 23일
0

연습문제

목록 보기
10/15
  • 신장트리 :
    그래프에서 모든 노드를 포함하면서 사이클이 존재하지 않는 부분 그래프
    최소신장트리를 구하기 위해서? -> 크루스칼 알고리즘 활용
  • 크루스칼 알고리즘 (그리디 알고리즘에 포함)
    1. 간선 데이터를 비용에 따라 오름차순 정렬
    2. 간선을 하나씩 확인하며 현재의 간선이 사이클을 포함시키는지 확인
      • 사이클이 발생하지 않는 경우 최소신장트리에 포함
      • 사이클이 발생하는 경우 최소신장트리에 비포함
    3. 모든 간선에 대해 2번 과정을 반복

💻 코드

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 nodeA;
    }

    public int getNodeB() {
        return nodeB;
    }

    @Override
    public int compareTo(Edge other)
    {
        if (this.distance < other.distance)
            return -1; // 오름차순 정렬
        return 1;
    }
}

public class Kruskal
{
    // 노드의 개수(V)와 간선(Union 연산)의 개수(E)
    // 노드의 개수는 최대 100,000개라고 가정
    public static int v, e;
    public static int[] parent = new int[100001];
    // 모든 간선을 담을 리스트와, 최종 비용을 담을 변수
    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 x, int y)
    {
        x = findParent(x);
        y = findParent(y);
        if(x < y) parent[y] = x;
        else parent[x] = y;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        v = sc.nextInt();
        e = sc.nextInt();

        // 부모 테이블상에서, 부모를 자기 자신으로 초기화
        for(int x = 0; x <= v; x++)
            parent[x] = x;

        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;
            }
        }

        System.out.println(result);
    }
}

📝 정리

크루스칼 알고리즘은 간선의 개수가 E일 때 Elog(E)의 시간 복잡도를 가짐.
간선의 정렬에 대해 시간을 가장 많이 소요함. (O(ElogE)

profile
글 연습, 정보 수집

0개의 댓글