알고리즘 관련/BOJ

2887 행성 터널

Andrew-Yun 2021. 10. 28. 11:29

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

 

2887번: 행성 터널

첫째 줄에 행성의 개수 N이 주어진다. (1 ≤ N ≤ 100,000) 다음 N개 줄에는 각 행성의 x, y, z좌표가 주어진다. 좌표는 -109보다 크거나 같고, 109보다 작거나 같은 정수이다. 한 위치에 행성이 두 개 이

www.acmicpc.net

고찰: 처음엔 크루스칼 알고리즘을 수행하기 위해 단순히 행성끼리 간선을 모두 연결하여 정렬하면 되겠다라고 생각한 순간 메모리 초과가 떴다..

행성의 최대 개수인 N이 10만인 것을 간과하고 N^2 으로 접근해서 그런 것 같다.

 

풀이: 문제의 조건 중 간선의 비용을 min (|x1 - x2|, |y1 - y2|, |z1 - z2|)로 계산한다는 것에 집중하자.

모든 간선을 연결하지 않고, 행성 간의 x, y, z 좌표 값을 기준으로 정렬하여 0~N - 1까지 간선을 만들어 연결하는 방식이다. 중복되는 간선이 있을 수 있지만 상관없다. 어차피 최소 비용만 만족하면 되기 때문이다.

이렇게 모든 간선을 만들면, nlogn * 3 + n의 시간이 들고 이후 만들어진 간선을 가지고 크루스칼 알고리즘을 수행하면 된다.

 

정답코드

더보기
import java.io.*;
import java.util.*;

class Edge implements Comparable<Edge>{
    int idx1, idx2; //(행성의 인덱스)
    long dist;
    public Edge(int idx1, int idx2, long dist) {
        this.idx1 = idx1;
        this.idx2 = idx2;
        this.dist = dist;
    }

    @Override
    public int compareTo(Edge e) {
        if(this.dist < e.dist){
            return -1;
        }
        else if(this.dist > e.dist){
            return 1;
        }
        return 0;
    }
}
class Planet {
    int idx; //행성의 좌표 (x, y, z 중 하나)
    int point;
    public Planet(int idx, int point){
        this.idx = idx;
        this.point = point;
    }
}
public class Main{
    public static int N;
    public static long answer;
    public static Planet[] x, y, z;
    public static int parents[];
    public static void _union(int a, int b){
        a = getParent(a);
        b = getParent(b);
        if(a < b)
            parents[b] = a;
        else
            parents[a] = b;
    }
    public static int getParent(int a){
        if(a == parents[a]){
            return a;
        }
        return parents[a] = getParent(parents[a]);
    }
    public static boolean find(int a, int b){
        a = getParent(a);
        b = getParent(b);
        if(a == b)
            return true;
        else
            return false;
    }
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        List<Edge> edges = new ArrayList<>();
        x = new Planet[N];  y = new Planet[N]; z = new Planet[N];
        parents = new int[N + 1];
        for(int i = 0; i < N; i++){
            parents[i] = i;
        }
        for(int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            x[i] = new Planet(i, Integer.parseInt(st.nextToken()));
            y[i] = new Planet(i, Integer.parseInt(st.nextToken()));
            z[i] = new Planet(i, Integer.parseInt(st.nextToken()));
        }
        Arrays.sort(x, (p1, p2) -> p1.point - p2.point);
        for(int i = 0; i < N - 1; i++){
            edges.add(new Edge(x[i].idx, x[i + 1].idx, Math.abs(x[i].point - x[i + 1].point)));
        }
        Arrays.sort(y, (p1, p2) -> p1.point - p2.point);
        for(int i = 0; i < N - 1; i++){
            edges.add(new Edge(y[i].idx, y[i + 1].idx, Math.abs(y[i].point - y[i + 1].point)));
        }
        Arrays.sort(z, (p1, p2) -> p1.point - p2.point);
        for(int i = 0; i < N - 1; i++){
            edges.add(new Edge(z[i].idx, z[i + 1].idx, Math.abs(z[i].point - z[i + 1].point)));
        }
        Collections.sort(edges);
        for(Edge e : edges){
            if(!find(e.idx1, e.idx2)){
                _union(e.idx1, e.idx2);
                answer += e.dist;
            }
        }
        System.out.println(answer);
    }
}