알고리즘/백준

백준 2887 - 행성 터널

D_Helloper 2022. 10. 30. 18:01

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

 

2887번: 행성 터널

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

www.acmicpc.net

 

문제 설명

때는 2040년, 이민혁은 우주에 자신만의 왕국을 만들었다. 왕국은 N개의 행성으로 이루어져 있다. 민혁이는 이 행성을 효율적으로 지배하기 위해서 행성을 연결하는 터널을 만들려고 한다.

행성은 3차원 좌표위의 한 점으로 생각하면 된다. 두 행성 A(xA, yA, zA)와 B(xB, yB, zB)를 터널로 연결할 때 드는 비용은 min(|xA-xB|, |yA-yB|, |zA-zB|)이다.

민혁이는 터널을 총 N-1개 건설해서 모든 행성이 서로 연결되게 하려고 한다. 이때, 모든 행성을 터널로 연결하는데 필요한 최소 비용을 구하는 프로그램을 작성하시오.

 

입력

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

 

문제 풀이

특정 좌표를 기준으로 정렬을 하면 위에서부터 아래로 인접한 행성이 가장 가까운 행성이 될 것이라고 생각했다.

그래서 x,y,z를 기준으로 정렬을 3번 진행한 후에, 터널 건설의 비용을 모두 List에 넣고 Prim 알고리즘을 활용해 최저 비용을 구했다.

2번째 요소를 넣을 때 for문을 1부터 시작해서 계속 틀렸다. 인덱스 관리 잘하자.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class Main {
	static class Node implements Comparable<Node>{
		long Node,weight;

		public Node(long Node, long weight) {
			super();
			this.Node = Node;
			this.weight = weight;
		}

		@Override
		public int compareTo(Node o) {
			// TODO Auto-generated method stub
			return (int) (this.weight-o.weight);
		}
	}
	static long[][] map;
	static boolean[] visited;
	
	static int N;
	static long answer;
	static List<Node>[] list;
	static PriorityQueue<Node> pq = new PriorityQueue<>();
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		N = Integer.parseInt(st.nextToken());
		map = new long[N][4];
		list = new List[N+1];
		visited = new boolean[N+1];
		for(int i=0; i<N+1;i++) {
			list[i] = new ArrayList<>();
		}
		for(int i=0; i<N; i++) {
			st = new StringTokenizer(br.readLine());
			for(int j=0; j<3; j++) {
				map[i][j] = Integer.parseInt(st.nextToken());
			}
			map[i][3] = i+1;
		}
        //0번째 요소로 정렬(x)
		Arrays.sort(map, (o1, o2) -> {
            return Long.compare(o1[0], o2[0]);
        });
		//0번째 요소로 정렬된 값 insert
		for(int i=0; i<N-1; i++) {
			list[(int) map[i][3]].add(new Node(map[i+1][3],Math.abs(map[i][0]-map[i+1][0])));
			list[(int) map[i+1][3]].add(new Node(map[i][3], Math.abs(map[i][0]-map[i+1][0])));
		}
		
		//1번째 요소로 정렬(y)
		Arrays.sort(map, (o1, o2) -> {
            return Long.compare(o1[1], o2[1]);
        });
		//1번째 요소로 정렬된 값 insert
		for(int i=0; i<N-1; i++) {
			list[(int) map[i][3]].add(new Node(map[i+1][3],Math.abs(map[i][1]-map[i+1][1])));
			list[(int) map[i+1][3]].add(new Node(map[i][3], Math.abs(map[i][1]-map[i+1][1])));
		}
        //2번째 요소로 정렬(z)
		Arrays.sort(map, (o1, o2) -> {
            return Long.compare(o1[2], o2[2]);
        });
		//2번째 요소로 정렬된 값 insert
		for(int i=0; i<N-1; i++) {
			list[(int) map[i][3]].add(new Node(map[i+1][3],Math.abs(map[i][2]-map[i+1][2])));
			list[(int) map[i+1][3]].add(new Node(map[i][3], Math.abs(map[i][2]-map[i+1][2])));
		}
		
		//prim 진행
		pq.add(new Node(1,0));
		while(!pq.isEmpty()) {
			Node temp = pq.poll();
			if(visited[(int) temp.Node]) continue;
			int to = (int) temp.Node;
			long weight = temp.weight;
			visited[to] = true;
			answer+=weight;
			for(Node next : list[to]) {
				if(!visited[(int) next.Node]) {
					pq.add(next);
				}
			}
		}
		System.out.println(answer);
	}
}