BOJ: 1708 볼록 껍질

1 분 소요

문제

다각형의 임의의 두 꼭짓점을 연결하는 선분이 항상 다각형 내부에 존재하는 다각형을 볼록 다각형이라고 한다. 아래 그림에서 (a)는 볼록 다각형이며, (b)는 볼록 다각형이 아니다.

Figure

조금만 생각해 보면 다각형의 모든 내각이 \(180\)도 이하일 때 볼록 다각형이 된다는 것을 알 수 있다. 편의상 이 문제에서는 \(180\)도 미만인 경우만을 볼록 다각형으로 한정하도록 한다.

\(2\)차원 평면에 \(N\)개의 점이 주어졌을 때, 이들 중 몇 개의 점을 골라 볼록 다각형을 만드는데, 나머지 모든 점을 내부에 포함하도록 할 수 있다. 이를 볼록 껍질 (CONVEX HULL) 이라 한다. 아래 그림은 \(N=10\)인 경우의 한 예이다.

Figure

점의 집합이 주어졌을 때, 볼록 껍질을 이루는 점의 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 점의 개수 \(N(3 \leq N \leq 100,000)\)이 주어진다. 둘째 줄부터 \(N\)개의 줄에 걸쳐 각 점의 \(x\)좌표와 \(y\)좌표가 빈 칸을 사이에 두고 주어진다. 주어지는 모든 점의 좌표는 다르다. \(x\)좌표와 \(y\)좌표의 범위는 절댓값 \(40,000\)을 넘지 않는다. 입력으로 주어지는 다각형의 모든 점이 일직선을 이루는 경우는 없다.

출력

첫째 줄에 볼록 껍질을 이루는 점의 개수를 출력한다.

볼록 껍질의 변에 점이 여러 개 있는 경우에는 가장 양 끝 점만 개수에 포함한다.

예제 입력 1

8
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2

예제 출력 1

5


코드

#include <bits/stdc++.h>

using namespace std;

struct point {
    int x, y;
};

bool isNotRightTurn(const point &a, const point &b, const point &c) {
    long long cross = (long long)(a.x - b.x) * (c.y - b.y) - (long long)(a.y - b.y) * (c.x - b.x);
    long long dot = (long long)(a.x - b.x) * (c.x - b.x) + (long long)(a.y - b.y) * (c.y - b.y);
    return cross < 0 || (cross == 0 && dot <= 0);
}

vector<point> convex_hull(vector<point> points) {
    sort(points.begin(), points.end(), [](auto a, auto b) { return a.x < b.x || (a.x == b.x && a.y < b.y); });
    int n = points.size();
    vector<point> hull;
    for (int i = 0; i < 2 * n - 1; i++) {
        int j = i < n ? i : 2 * n - 2 - i;
        while (hull.size() >= 2 && isNotRightTurn(hull.end()[-2], hull.end()[-1], points[j]))
            hull.pop_back();
        hull.push_back(points[j]);
    }
    hull.pop_back();
    return hull;
}

int main() {
    vector<point> p;
    point pt;
    int t;

    cin>>t;

    for(int i=0; i<t; i++) {
        cin>>pt.x>>pt.y;
        p.push_back(pt);
    }

    vector<point> hull1 = convex_hull(p);
    cout << hull1.size() << endl;
}

Reference

BOJ

태그:

카테고리:

업데이트:

댓글남기기