[분류]

  • 서로소 집합
  • 최소신장트리



[문제링크]

[요구사항]

  1. N개의 행성들을 모두 연결할 수 있는 터널 N-1개를 만드는데 필요한 최소비용을 구하여라.

[풀이]

  1. union find가 사용되는 Kruskal 알고리즘을 사용하여 최소신장트리를 구현하면 문제를 해결할 수 있다.

  2. 일반적인 문제와 다르게 x,y,z좌표 모두를 고려해야하는데, 완전히 좌표별로 별개로 생각한다.

  3. 우선 x,y,z 좌표별로 따로 sorting을 한 다음 비용을 각각 구한다.

  4. 이후 edge들을 모두 저장하고 cost에 따라 sorting한다.

  5. N-1개의 터널을 구할 때까지 반복해서 구한다.

[코드]

//baekjoon_2887_행성 터널

import java.io.*;
import java.lang.*;
import java.util.*;
public class Main {
    static int n;
    static int parent[];
    static int rank[];
    static ArrayList<Info> x = new ArrayList<>();
    static ArrayList<Info> y = new ArrayList<>();
    static ArrayList<Info> z = new ArrayList<>();
    static PriorityQueue<Edge> edges = new PriorityQueue<>();
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] s = br.readLine().split(" ");
        n = Integer.parseInt(s[0]);

        parent = new int[n+1];
        rank = new int[n+1];
        for(int i=0;i<n+1;i++){
            parent[i]=i;
            rank[i]=0;
        }//부모는 모두 자기 자신으로 초기화

        for(int i=0;i<n;i++){
            s = br.readLine().split(" ");
            x.add(new Info(Integer.parseInt(s[0]), i));
            y.add(new Info(Integer.parseInt(s[1]), i));
            z.add(new Info(Integer.parseInt(s[2]), i));
        }

        Collections.sort(x);
        Collections.sort(y);
        Collections.sort(z);

        Info before = x.get(0);
        for(int i=1;i<x.size();i++){
            Info info = x.get(i);
            edges.add(new Edge(info.num-before.num, info.idx, before.idx));
            before = info;
        }

        before = y.get(0);
        for(int i=1;i<y.size();i++){
            Info info = y.get(i);
            edges.add(new Edge(info.num-before.num, info.idx, before.idx));
            before = info;
        }

        before = z.get(0);
        for(int i=1;i<z.size();i++){
            Info info = z.get(i);
            edges.add(new Edge(info.num-before.num, info.idx, before.idx));
            before = info;
        }

        int cnt = 1;
        int total = 0;
        while(cnt<=n-1){
            Edge edge = edges.poll();
            int x = find(edge.x);
            int y = find(edge.y);

            if(x==y) continue;
            union(x, y);
            total+=edge.cost;
            cnt++;
        }
        System.out.println(total);
    }

    public static void union(int x, int y){
        x = find(x);
        y = find(y);

        if(x==y) return;

        if(rank[x]>rank[y]){
            parent[y]=x;
        }else{
            parent[x]=y;
            if(rank[x]==rank[y]){
                rank[y]++;
            }
        }
    }

    public static int find(int x){
        if(parent[x]==x) return x;

        return parent[x]=find(parent[x]);
    }

    public static class Edge implements Comparable<Edge>{
        int cost;
        int x;
        int y;

        public Edge(int cost, int x, int y){
            this.cost = cost;
            this.x = x;
            this.y = y;
        }

        @Override
        public int compareTo(Edge o){
            return this.cost-o.cost;
        }
    }

    public static class Info implements Comparable<Info>{
        int num;
        int idx;

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

        @Override
        public int compareTo(Info o){
            return this.num - o.num;
        }
    }
}



[통과여부]

image



[느낀점]

x, y, z 좌표가 모두 따로 있어서 일일히 다 비교해서 최소거리를 구해줘야하나 싶었는데 다 따로 생각하고 넣으면 되어서 신선했다.