본문 바로가기
알고리즘

컨벡스 헐 (Convex hull)

by 출근길 2018. 7. 17.

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Stack;
import java.util.StringTokenizer;
 
 
class Edge {
    int x;
    int y;
     
    Edge (int x, int y){
        this.x = x;
        this.y = y;
    }
}
 
public class ConvexHull {
     
    /*
     * 볼록 껍질
     * https://www.acmicpc.net/problem/1708
     */
     



   static int MINY;
    static int MINX;
 
    public static void main(String[] args) throws IOException {
         
 
        /*
         * 1. Convex hull 생성
         * 1) 최하단, 좌측점을 기준
         * 2) 점을 각도순으로 정렬
         * 3) CCW사용
         * 3.2) 양수 > 0 : STACK에 다음점을 넣고 PASS
         * 3.3) 음수 < 0 : STACK의 마지막 원소 제거, repeat
         */
         
        //System.setIn(new FileInputStream("res/seminar/sample_input.txt"));
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
         
        int T = Integer.parseInt(br.readLine());
        for (int Ti = 1; Ti <= T; Ti++){
 
            int N = Integer.parseInt(br.readLine());
             
            ArrayList A = new ArrayList();
             
            StringTokenizer ST;
            MINY = Integer.MAX_VALUE;
            MINX = Integer.MAX_VALUE;
            for (int i = 1; i <= N; i++){
                ST = new StringTokenizer(br.readLine());
                int x = Integer.parseInt(ST.nextToken());
                int y = Integer.parseInt(ST.nextToken());
                 
                // 1) 최하단, 좌측점을 기준
                if (y < MINY){
                    MINY = y;
                    MINX = x;
                      
                } else if (y == MINY){
                    if (x < MINX){
                        MINY = y;
                        MINX = x;
                    }
                }
                A.add(new Edge(x, y));
            }
             
            // 2) 점을 각도순으로 정렬
             
                Collections.sort(A, new Comparator() {
 
                    @Override
                    public int compare(Edge arg0, Edge arg1) {
                        int ret = ccw(MINX, MINY, arg0.x, arg0.y, arg1.x, arg1.y);
                         
                        if (ret == 1){
                            return -1;
                        } else if (ret == -1){
                            return 1;
                        } else if (ret == 0) {
                            long a = dist(MINX, MINY, arg0.x, arg0.y);
                            long b = dist(MINX, MINY, arg1.x, arg1.y);
                             
                            if (a < b){
                                return -1;
                            } else if (a > b) {
                                return 1;
                            } else if  (a == b) {
                                return 0;
                            }
                        }
                        return 0;
                         
                    }
                });
     
             
            /*
             * 4) STACK과 CCW사용
             * 4.1 CCW(STACK의 마지막 두점, 다음점)
             * 4.2 양수 > 0 : STACK에 다음점을 넣고 PASS
             * 4.3 음수 < 0 : STACK의 마지막 원소 제거, repeat
             */
             
            A.add(new Edge(MINX, MINY));
            Edge XY2 = null
            Edge XY1 = null
            Edge NEXT = null;
            Stack CVH = new Stack();
             
            //0번점, 1번점 stack에 push
            CVH.push(A.get(0));
            CVH.push(A.get(1));
             
             
            for (int i = 2; i < N; i++) {
                while (CVH.size() >= 2){
                    NEXT = A.get(i);
                    XY2 = CVH.pop();
                    XY1 = CVH.peek();               
                     
                    if (ccw(XY1.x, XY1.y, XY2.x, XY2.y, NEXT.x, NEXT.y) > 0){
                        CVH.push(XY2);
                        break;
                    } 
                }
                CVH.push(NEXT);
            }
            bw.write("#"+Ti+" "+CVH.size()+"\n");
             
        }
         
        br.close();
        bw.flush();
        bw.close();
    }
     
    static int ccw(long x1, long y1, long x2, long y2, long x3, long y3) {
        long ret = (x1 * y2 + x2 * y3 + x3 * y1) - (x3 * y2 + x2 * y1 + x1 * y3);
 
        if (ret > 0)
            return 1;
        else if (ret == 0)
            return 0;
        else
            return -1;
    }
 
    static long dist(long x1, long y1, long x2, long y2) {
        return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
    }
 
}

'알고리즘' 카테고리의 다른 글

SPFA (Shortest Path Faster Algorithm)  (0) 2018.07.17
인덱스 트리 (Indexed Tree)  (0) 2018.07.17
플로이드 워셜 (Floyd Warshall)  (0) 2018.07.17
다익스트라 (Dijkstra)  (0) 2018.07.17
DFS (Stack)  (0) 2018.07.17
DFS, BFS  (0) 2018.07.17
이분탐색 (Binary Search)  (0) 2018.07.17
CCW  (0) 2017.12.12