Algorithm

[백준 2887 - JAVA] 행성터널

메징징 2020. 11. 9. 18:09
반응형
 

2887번: 행성 터널

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

www.acmicpc.net

모든 행성을 터널로 연결하는데 필요한 최소 비용을 출력한다!

간선을 찾고 MST로 연결하는 것은 쉽지만,

행성의 개수가 100,000개로 시간초과 혹은 메모리 초과가 발생하는 문제다.

나같은 경우에도 메모리 초과를 3번 겪고난 후 다른 블로그를 참고하여 문제를 해결했다.

 

 

풀이 방법

  1. 각 행성의 Index와 x, y, z를 저장하고 Union-Find에서 사용할 배열을 초기화한다.
  2. 행성들의 거리를 계산하여 간선으로 PQ에 삽입한다.

    2-1. 모든 간선을 삽입할 경우 시간초과, 메모리 초과가 발생한다.

    2-2. 간선을 최소화로 넣기 위하여 X, Y, Z 각각을 기준으로 정렬 후 가까운 행성끼리의 간선만을 삽입한다.

  3. 크루스칼 알고리즘을 사용하여 최소 신장 부분 그래프를 완성한다.

 

 

 

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

public class Main {
	public static class Planet {
		int idx;
		int x, y, z;
		public Planet(int idx, int x, int y, int z) {
			this.idx = idx;
			this.x = x;
			this.y = y;
			this.z = z;
		}
	}
	
	public static int N;
	public static int ans;
	public static int[] p;
	public static Planet[] planets;
	public static PriorityQueue<int[]> pq;
	
	public static void union(int x, int y) {
		p[findSet(y)] = p[findSet(x)];
	}
	public static int findSet(int x) {
		if (p[x] == x) return x;
		return p[x] = findSet(p[x]);
	}
	
	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;
		pq = new PriorityQueue<int[]>(new Comparator<int[]>() {
			@Override
			public int compare(int[] o1, int[] o2) {
				return Integer.compare(o1[2], o2[2]);
			}
		});
		N = Integer.parseInt(br.readLine());
		planets = new Planet[N];
		p = new int[N];
		for (int i = 0; i < N; i++) {
			st = new StringTokenizer(br.readLine());
			int x = Integer.parseInt(st.nextToken());
			int y = Integer.parseInt(st.nextToken());
			int z = Integer.parseInt(st.nextToken());
			planets[i] = new Planet(i, x, y, z);
			p[i] = i;
		}
		
		createEdge();
		int cnt = 0;
		while(!pq.isEmpty()) {
			int[] cur = pq.poll();
			if (findSet(cur[0]) != findSet(cur[1])){
				ans+=cur[2];
				if (++cnt == N-1) break;
				union(cur[0], cur[1]);
			}
		}
		
		System.out.println(ans);
	}
	
	public static void createEdge() {
		Arrays.sort(planets, new Comparator<Planet>() {
			@Override
			public int compare(Planet o1, Planet o2) {
				return Integer.compare(o1.x, o2.x);
			}
		});
		for (int i = 1; i < N; i++) {
			int dis = Math.abs(planets[i].x-planets[i-1].x);
			pq.add(new int[] {planets[i].idx, planets[i-1].idx, dis});
		}
		
		Arrays.sort(planets, new Comparator<Planet>() {
			@Override
			public int compare(Planet o1, Planet o2) {
				return Integer.compare(o1.y, o2.y);
			}
		});
		for (int i = 1; i < N; i++) {
			int dis = Math.abs(planets[i].y-planets[i-1].y);
			pq.add(new int[] {planets[i].idx, planets[i-1].idx, dis});
		}
		
		Arrays.sort(planets, new Comparator<Planet>() {
			@Override
			public int compare(Planet o1, Planet o2) {
				return Integer.compare(o1.z, o2.z);
			}
		});
		for (int i = 1; i < N; i++) {
			int dis = Math.abs(planets[i].z-planets[i-1].z);
			pq.add(new int[] {planets[i].idx, planets[i-1].idx, dis});
		}
	}
}