Blog Content

    티스토리 뷰

    [기하/개념] 볼록 껍질 (Convex Hull)

    1. list[] 에 있는 점들 중 가장 작은 것을 찾아서 기준점으로 선정한다.

    2. 기준점 기준으로 각각의 점들을 반시계 방향으로 기준점과 각도 순서대로 정렬한다.

    3. 점들을 하나씩 보면서 볼록껍질에 포함시킬지 말지를 결정한다.

    스택을 하나 만들고, 이 스택에는 점의 번호를 넣어주는데 스택 사이즈가 한개밖에 없으면

    일단 지금 잡고 있는 점을 넣는다.

    스택에 점이 두 개 이상이면 비교를 한다.

    점 두개를 기준으로 다른 점을 봤을 때 CCW를 하는데, 이 때 반시계 방향에 있으면 만족하므로 스택에 넣어준다.

    그리고나서 또 스택의 두개를 빼서 두 점 기준으로 다음 점을 CCW 한다.

    만약 반시계 방향에 없다면 오목하다는 의미이므로 만족하지 않는다. 따라서 이럴 경우에는 스택에서 빼준다.

    이렇게 계속 반복해준다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.util.Arrays;
    import java.util.Comparator;
    import java.util.Stack;
    import java.util.StringTokenizer;
     
    class Hull{
        int x, y;
        Hull(int x, int y){
            this.x = x;
            this.y = y;
        }
    }
    public class temp {
        static int N;
        static Hull list[];
        
        public static void main(String[] args) throws Exception {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
            StringTokenizer st;
            
            N = Integer.parseInt(br.readLine());
            list = new Hull[N+1];
            for(int i=1; i<=N; i++){
                st = new StringTokenizer(br.readLine());
                int a = Integer.parseInt(st.nextToken());
                int b = Integer.parseInt(st.nextToken());
                
                list[i] = new Hull(a, b);
            }
            // 1. 기준점 선정
            for(int i=1; i<=N; i++){
                if(list[1].y > list[i].y || list[1].y == list[i].y && list[1].x > list[i].x){
                    Hull temp = list[1];
                    list[1= list[i];
                    list[i] = temp;
                }
            }
            
            // 2. 기준점 기준으로 반시계방향으로 정렬
            Arrays.sort(list, 2, N+1new Comparator<Hull>() {
     
                @Override
                public int compare(Hull a, Hull b) {
                    // TODO Auto-generated method stub
                    int v = ccw(new Hull(list[1].x, list[1].y), a, b);
                    if( v > 0)    return -1;
                    if(v<0)    return 1;
                    return (Math.abs(a.x) + a.y) - (Math.abs(b.x) + b.y);
                }
            });    
            // 3. stack 
            Stack<Integer> stack = new Stack<>();
            stack.push(1);
            for(int i=2; i<=N; i++){
                while(stack.size() > 1 && ccw(list[stack.get(stack.size()-2)], list[stack.peek()], list[i]) <=0 ){
                    stack.pop();
                }
                stack.add(i);
            }
            bw.write(stack.size() + "\n");
            bw.flush();
        }
        protected static int ccw(Hull A, Hull B, Hull C) {
            long cal = 0;
            cal = (long)(B.x - A.x) * (C.y - A.y) - (long)(C.x-A.x) * (B.y-A.y);
            if(cal > 0)    return 1;
            else if (cal< 0)    return -1;
            else    return 0;
        }
        
     
    }
     
    cs


    Comments