Coding Test/백준

[백준] 1196 최소 스패닝 트리 - 자바

lsh2613 2023. 9. 19. 16:30

https://www.acmicpc.net/problem/1197

 

1197번: 최소 스패닝 트리

첫째 줄에 정점의 개수 V(1 ≤ V ≤ 10,000)와 간선의 개수 E(1 ≤ E ≤ 100,000)가 주어진다. 다음 E개의 줄에는 각 간선에 대한 정보를 나타내는 세 정수 A, B, C가 주어진다. 이는 A번 정점과 B번 정점이

www.acmicpc.net

문제 풀이

최소 스패닝 트리(MST)를 구하는 알고리즘으로 크루스칼, 프림이 있다. 두 알고리즘 모두 연습할 겸 두 가지 방법 모두 사용해 보았다.

자세한 이론은 생략하고 두 알고리즘을 간단하게 비교한 표를 살펴보자.

최소 신장 트리 (MST) 탐색 순서  방문 체크  비고
크루스칼(Kruskal) 최소 비용 간선부터 시작 union-find  
프림(Prim) 임의 정점에서 최소 비용 간선을 갖는 인접 정점부터 시작 visited[] 최소 간선을 갖는 인접 노드를 다루기 위해 Priority Queue 사용

코드 - Kruskal

package 백준;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

class Edge{
    int from;
    int to;
    int cost;

    public Edge(int from, int to, int cost) {
        this.from = from;
        this.to = to;
        this.cost = cost;
    }
}

public class b1197_Kruskal {
    static Edge[] edges;
    static int[] parent;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int V = Integer.parseInt(st.nextToken());
        int E = Integer.parseInt(st.nextToken());

        edges = new Edge[E];
        parent = new int[V + 1];
        for (int i = 0; i < V + 1; i++) {
            parent[i] = i;
        }

        for (int i = 0; i < E; i++) {
            st = new StringTokenizer(br.readLine());
            int from = Integer.parseInt(st.nextToken());
            int to = Integer.parseInt(st.nextToken());
            int cost = Integer.parseInt(st.nextToken());

            edges[i] = new Edge(from, to, cost);
        }

        Arrays.sort(edges, (e1, e2) -> e1.cost - e2.cost);

        int weight = 0; // 가중치
        int mstEdges = 0; // 최소스패닝트리의 간선 갯수
        for (int i = 0; i < E; i++) {
            Edge edge = edges[i];
            int from = edge.from;
            int to = edge.to;
            int cost = edge.cost;

            if (union(from, to)) {
                weight += cost;
                mstEdges++;

                if (mstEdges == E - 1) {
                    break;
                }
            }
        }

        System.out.println(weight);
    }

    static boolean union(int a, int b) {
        int rootA = find(a);
        int rootB = find(b);

        if (rootA == rootB)
            return false;

        parent[rootB] = rootA;
        return true;
    }

    static int find(int n) {
        if (parent[n] != n)
            parent[n] = find(parent[n]);

        return parent[n];
    }
}

 

코드 - Prim

package 백준;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

class Node{
    int idx;
    int cost;

    public Node(int idx, int cost) {
        this.idx = idx;
        this.cost = cost;
    }
}

public class b1197_Prim {
    static int V, E;
    static List<Node>[] tree;
    static boolean[] visited;

    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());
        E = Integer.parseInt(st.nextToken());

        tree = new ArrayList[V + 1];
        for (int i = 1; i < V + 1; i++) {
            tree[i] = new ArrayList<>();
        }

        for (int i = 0; i < E; i++) {
            st = new StringTokenizer(br.readLine());
            int from = Integer.parseInt(st.nextToken());
            int to = Integer.parseInt(st.nextToken());
            int cost = Integer.parseInt(st.nextToken());

            tree[from].add(new Node(to, cost));
            tree[to].add(new Node(from, cost));
        }

        System.out.println(prim());
    }

    static int prim() {
        int weight = 0;
        visited = new boolean[V + 1];

        Queue<Node> pq = new PriorityQueue<>((n1, n2) -> n1.cost - n2.cost);
        pq.offer(new Node(1, 0));  // 임의의 간선부터 시작

        while (!pq.isEmpty()) {
            Node now = pq.poll();
            int idx = now.idx;
            int cost = now.cost;

            if (visited[idx]) continue;
            // MST 간선 추가
            visited[idx] = true;
            weight += cost;

            for (Node adj : tree[idx]) {
                if (!visited[adj.idx])
                    pq.offer(adj);
            }
        }

        return weight;
    }
}