백준 4386 별자리 만들기 [자바]

baekjoon 4386 별자리 만들기

java

문제 분석

  • 별들의 좌표가 양의 실수로 주어진다.
  • 모든 별을 이으면서, 선분의 길이의 합이 최소가 되는 별자리의 선분의 길이를 구해라.

입력조건

별의 개수 N
N줄에 걸쳐서 {
	별자리의 좌표 x, y
}

풀이과정

  • 최소 스패닝 트리
  • 주어지는 별들에 번호를 매기고, 모든 별에서 별로 가는 길이를 구해서 간선 배열로 만듬.
  • 이 간선 배열을 이용하여,
    크루스칼 알고리즘으로 최소 스패닝 트리를 구함.

코드 구성

  • 서로소 집합(유니온 파인드)

    public static int parent(int x) {
        if(p[x] == x) return x;
        else return p[x] = parent(p[x]);
    }
    public static void union(int x, int y) {
        p[parent(y)] = parent(x);
    }
    
  • 크루스칼 알고리즘

    p = new int[N];
    for(int i = 0; i < N; i++) p[i] = i;
      
    int selected = 0;
    double cost = 0;
    while(selected < N-1) {
        vertex now = pq.poll();
      
        if(parent(now.u) == parent(now.v)) continue;
      
        selected++;
        cost += now.w;
        union(now.u, now.v);
    }
    
  • 입력받은 좌표를 이용하여, 간선 구해놓기.

    double[][] map = new double[N][2];
    for(int i = 0; i < N; i++) {
        StringTokenizer st = new StringTokenizer(br.readLine());
        map[i][0] = Double.parseDouble(st.nextToken());
        map[i][1] = Double.parseDouble(st.nextToken());
    }
    // 입력 완료
      
    PriorityQueue<vertex> pq = new PriorityQueue<>();
    for(int i = 0; i < N; i++) {
        for(int j = i+1; j < N; j++) {
            double dist = Math.sqrt(Math.pow(map[i][0] - map[j][0], 2) + Math.pow(map[i][1] - map[j][1], 2));
            pq.add(new vertex(i, j, dist));
        }
    }
    // 자료 정리 완료
    

전체 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class BJ4386_별자리만들기 {
	static int[] p;
	static class vertex implements Comparable<vertex> {
		int u, v;
		double w;
		vertex(int u, int v, double w) {
			this.u = u;
			this.v = v;
			this.w = w;
		}
		@Override
		public int compareTo(vertex o) {
			return Double.compare(this.w, o.w);
		}
	}
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int N = Integer.parseInt(br.readLine());
		
		double[][] map = new double[N][2];
		for(int i = 0; i < N; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			map[i][0] = Double.parseDouble(st.nextToken());
			map[i][1] = Double.parseDouble(st.nextToken());
		}
		// 입력 완료
		
		PriorityQueue<vertex> pq = new PriorityQueue<>();
		for(int i = 0; i < N; i++) {
			for(int j = i+1; j < N; j++) {
				double dist = Math.sqrt(Math.pow(map[i][0] - map[j][0], 2) + Math.pow(map[i][1] - map[j][1], 2));
				pq.add(new vertex(i, j, dist));
			}
		}
		// 자료 정리 완료
		
		p = new int[N];
		for(int i = 0; i < N; i++) p[i] = i;
		
		int selected = 0;
		double cost = 0;
		while(selected < N-1) {
			vertex now = pq.poll();
			
			if(parent(now.u) == parent(now.v)) continue;
			
			selected++;
			cost += now.w;
			union(now.u, now.v);
		}
		System.out.printf("%.2f", cost);
	}
	public static int parent(int x) {
		if(p[x] == x) return x;
		else return p[x] = parent(p[x]);
	}
	public static void union(int x, int y) {
		p[parent(y)] = parent(x);
	}
}