본문 바로가기
코딩테스트 준비/백준

[백준] 21924번 - 도시 건설 [Java]

by mwzz6 2025. 2. 11.

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

 

[백준] 21924번 - 도시 건설 [Java]
[백준] 21924번 - 도시 건설 [Java]
[백준] 21924번 - 도시 건설 [Java]


1.  아이디어

 

건물을 노드, 도로를 간선으로 생각했을 때 모든 건물이 도로를 통해 연결되도록 최소한의 도로로 만드는 것은 최소 스패닝 트리를 구하는 문제가 된다. 전체 비용에서 최소 스패닝 트리의 비용을 빼면 절약하는 비용이 된다.


2. 문제풀이

 

입력에서 전체 비용을 미리 계산 후 크루스칼 알고리즘으로 최소 스패닝 트리의 비용을 구하는 방식으로 구현했다. 이때 모든 건물이 연결되지 않으면 -1을 출력하기 위해 간선의 개수가 노드의 개수 - 1 이 되지 않으면 -1을 반환하도록 했다. 도로 비용의 합이 int형 범위를 넘어갈 수 있음에 주의해야 한다.


3. 코드

 

import java.io.*;
import java.util.*;

public class Main {

    private static class Edge implements Comparable<Edge> {
        int a;
        int b;
        int w;

        public Edge(int a, int b, int w) {
            this.a = a;
            this.b = b;
            this.w = w;
        }

        @Override
        public int compareTo(Edge o) {
            return Integer.compare(this.w, o.w);
        }
    }

    private static int[] p;

    private static int[] make(int N) {
        int[] arr = new int[1 + N];
        for (int i = 1; i <= N; i++) arr[i] = i;
        return arr;
    }

    private static int find(int x) {
        if (x == p[x]) return x;
        return p[x] = find(p[x]);
    }

    private static void union(int x, int y) {
        p[find(y)] = find(x);
    }

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

        int N = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());
        long sum = 0;

        PriorityQueue<Edge> edges = new PriorityQueue<>();
        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());
            int A = Integer.parseInt(st.nextToken());
            int B = Integer.parseInt(st.nextToken());
            int W = Integer.parseInt(st.nextToken());
            edges.add(new Edge(A, B, W));
            sum += W;
        }

        long min = kruskal(N, edges);
        if (min == -1) System.out.println(-1);
        else System.out.println(sum - min);
    }

    private static long kruskal(int N, PriorityQueue<Edge> edges) {
        p = make(N);

        long sum = 0;
        int cnt = 0;

        while (!edges.isEmpty()) {
            Edge e = edges.remove();
            if (find(e.a) == find(e.b)) continue;

            union(e.a, e.b);
            sum += e.w;
            cnt++;

            if (cnt == N - 1) return sum;
        }

        return -1;
    }

}

4. 후기