본문 바로가기
PS 문제 풀이/Baekjoon

[BOJ] 백준 2261 가장 가까운 두 점

by 까망 하르방 2021. 2. 28.
반응형

출처:  https://www.acmicpc.net/problem/2261

 Input 

4

0 0

10 10

0 10

10 0

 

 Output 

100 

Brute Force로 모든 점의 거리를 구한 후, 최소 거리를 구하면  O(N2)으로 TLE 발생

분할 정복 기법을 사용해 → O(N (logN)2)

 

① 모든 점을 x 좌표 기준 정렬 후,

 

② 중간 지점을 기준으로 두 개로 분할해서 x 구간거리가 

    일정 수준까지 작아지도록 재귀적으로 분할.

 

③ merge될 때, 좌측, 우측 부분에서 각각 가장 가까운 두 점 사이의 거리를 구합니다.

    좌측, 우측에서 구한 거리 중 더 작은 값을 구합니다.

    해당 값이 중간 기준위치를 지나는 왼쪽 점과 오른쪽 점 사이의 거리를 비교합니다.

 

ex) min(d1d2) = d를 구한 후, 중간 부분에서 d > d를 만족하는 거리(d3)를 구하면 됩니다. 

분할 과정을 통해 비교대상을 줄이기는 했지만,

최소 거리를 갱신하기 위해서는 어느정도 완전탐색으로 거리를 비교해야 합니다.

ex) 두 점 사이의 거리 = d = 5일 때, 코드상에서는 제곱처리하여  d * d하여 비교합니다.

 

④ 중간 부분에서도 마찬가지로 x 좌표상 거리가 d 이하인 점들끼리만 실제 거리를 비교합니다.

 

⑤ x 좌표간 거리가 d』 이하인 점들을 선별한 뒤로는 y 좌표 기준 정렬

     y 좌표간 거리가 d』 이하인 점들만 선별해서 두 점사이의 거리를 구합니다.


import java.io.*;
import java.util.*;
 
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = null;
        int N = Integer.parseInt(br.readLine());
        List<Point> arr = new ArrayList<>();
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            int x = Integer.parseInt(st.nextToken());
            int y = Integer.parseInt(st.nextToken());
            arr.add(new Point(x, y));
        }
 
        // x 좌표 기준 정렬
        Collections.sort(arr, new xComparator());
 
        // 정답 출력
        System.out.println(closest(arr, 0, N - 1));
    }
 
    static int closest(List<Point> arr, int left, int right) {
        int sectionSize = right - left + 1;
        // 분할된 x좌표상 크기가 3이하이면 
        if (sectionSize <= 3) { 
            // 가장 가까운 점의 거리를 구합니다.
            return bruteForce(arr, left, right);
        }
 
        int mid = (left + right) / 2;
        int leftSectionDistance = closest(arr, left, mid);
        int rightSectionDistance = closest(arr, mid + 1, right);
         
        // Left Side와 Right Side에서 구한 최소 거리 중 더 작은 값을 전체 구간 중 최소 거리로 임시 설정
        int answer = Math.min(leftSectionDistance, rightSectionDistance);
         
        List<Point> middleSection = new ArrayList<>(); // 왼쪽과 오른쪽 사이의 점들을 저장할 List
 
        for (int i = left; i <= right; i++) {
            // 중앙을 기준으로 거리를 비교 (제곱하기 때문에 음수는 무의미)
            int xDist = arr.get(i).x - arr.get(mid).x;
            // x 좌표간 거리가 현재 최소 거리 d 보다 작은 경우만 고려
            if (xDist * xDist < answer) {
                middleSection.add(arr.get(i));
            }
        }
 
        // y 좌표 기준으로 정렬 (이제 x좌표 기준은 무의미)
        Collections.sort(middleSection, new yComparator());
        int candidateSize = middleSection.size();
        for (int i = 0; i < candidateSize - 1; i++) {
            for (int j = i + 1; j < candidateSize; j++) {
                int yDist = middleSection.get(j).y - middleSection.get(i).y;
                if (yDist * yDist < answer) {
                    int dist = findDistance(middleSection.get(i), middleSection.get(j));
                    if (dist < answer) {
                        answer = dist;
                    }
                } 
                // y좌표 기준 오름차순 정렬했기 때문에 기준점과 가장 가까운 좌표가 answer보다 멀면
                // 다음 좌표들 비교는 무의미 하므로 break한 후, 다른 좌표를 기준으로 해서 반복
                else { 
                    break;
                }
            }
        }
        return answer;
    }
        // 완전 탐색으로 가장 가까운 거리 찾기
    static int bruteForce(List<Point> arr, int left, int right) { 
        int answer = Integer.MAX_VALUE;
        for (int i = left; i < right; i++) {
            for (int j = i + 1; j <= right; j++) {
                int temp = findDistance(arr.get(i), arr.get(j));
                if (answer > temp) {
                    answer = temp;
                }
            }
        }
        return answer;
    }
 
    // Euclidean Distance의 제곱
    static int findDistance(Point p1, Point p2) {
        return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
    }
}
 
class xComparator implements Comparator<Point> {
    // x 좌표 기준 정렬
    @Override
    public int compare(Point p1, Point p2) {
        return p1.x - p2.x;
    }
 
}
 
class yComparator implements Comparator<Point> {
    // y 좌표 기준 정렬
    @Override
    public int compare(Point p1, Point p2) {
        return p1.y - p2.y;
    }
 
}
 
class Point {
    int x, y;
 
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

 

반응형

'PS 문제 풀이 > Baekjoon' 카테고리의 다른 글

[BOJ] 백준 1100 하얀칸  (0) 2021.02.28
[BOJ] 백준 10950 A + B - 3  (0) 2021.02.28
[BOJ] 백준 11758 CCW  (0) 2021.02.28
[BOJ] 백준 4354 문자열 제곱  (0) 2021.02.28
[BOJ] 백준 3055 탈출  (0) 2021.02.27

댓글