볼록 껍질 (Convex Hull)
정의
볼록 껍질 (Convex Hull) 은 주어진 점 집합 P 를 모두 포함하는 최소 크기의 볼록 다각형. 즉 P 의 어떤 점도 다각형 외부에 있지 않고, 다각형의 꼭짓점은 P 의 일부 점.
표기: CH(P)
문제 상황과 동기
N 개의 2D 점이 흩어져 있을 때 이들을 모두 감싸는 최소 볼록 다각형을 찾는다.
- Naive: 모든 점 쌍에 대해 직선을 긋고, 모든 점이 한쪽에 있는지 검사. O(N^3).
- Graham scan (O(N log N)): 각도 정렬 후 스택.
- Andrew’s monotone chain (O(N log N)): x 좌표 정렬 후 상단 / 하단 hull 따로 구성. 구현이 더 간결.
핵심 통찰: 볼록 껍질은 볼록 다각형의 모든 꼭짓점이 CCW 방향을 만족한다. 스택에 넣고 CCW 조건이 깨지면 pop.
시각화
핵심 아이디어
CCW 판정
ccw(a, b, c) = (b - a) x (c - a)
= (b.x - a.x)*(c.y - a.y) - (b.y - a.y)*(c.x - a.x)
> 0 -> 반시계 (좌회전)
< 0 -> 시계 (우회전)
= 0 -> 일직선
볼록 껍질에서는 모든 인접 세 점이 일관된 방향 (시계 또는 반시계) 을 유지.
Andrew’s Monotone Chain (가장 널리 사용)
1. 점들을 x (같으면 y) 오름차순 정렬 // O(N log N)
2. Lower hull: 왼->오 sweep 하면서 ccw <= 0 이면 pop
3. Upper hull: 오->왼 sweep 하면서 ccw <= 0 이면 pop
4. 합치기 (중복 끝점 제거)
invariant: 스택의 마지막 두 점과 새 점이 항상 ccw > 0 (또는 < 0) 을 만족.
알고리즘
andrew_monotone_chain(P):
sort(P) // x, y 기준
lower = []
for p in P:
while len(lower) >= 2 and ccw(lower[-2], lower[-1], p) <= 0:
lower.pop()
lower.append(p)
upper = []
for p in reversed(P):
while len(upper) >= 2 and ccw(upper[-2], upper[-1], p) <= 0:
upper.pop()
upper.append(p)
return lower + upper[1:-1] // 끝점 중복 제거
구현
// Andrew's monotone chain O(N log N)
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
struct Point { ll x, y; };
ll ccw(Point a, Point b, Point c) {
return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
}
vector<Point> convex_hull(vector<Point>& p) {
sort(p.begin(), p.end(), [](auto& a, auto& b) {
return a.x < b.x || (a.x == b.x && a.y < b.y);
});
vector<Point> hull;
auto build = [&](int start, int end, int sign) {
for (int i = start; i != end; i += (end - start > 0 ? 1 : -1)) {
while ((int)hull.size() - start >= 2) {
auto& a = hull[hull.size() - 2];
auto& b = hull.back();
if (ccw(a, b, p[i]) * sign > 0) break;
hull.pop_back();
}
hull.push_back(p[i]);
}
};
build(0, p.size(), 1); // lower
int lower_sz = hull.size();
build(p.size() - 2, -1, 1); // upper (끝점 제외)
hull.pop_back(); // 시작점 중복 제거
return hull;
}
int main() {
vector<Point> pts = {{0,0},{1,1},{2,0},{1,-1},{0,1}};
auto hull = convex_hull(pts);
cout << "Convex Hull:\n";
for (auto& p : hull)
cout << "(" << p.x << ", " << p.y << ")\n";
}Convex Hull:
(0, 0)
(0, 1)
(1, 1)
(2, 0)
(1, -1)복잡도
| 항목 | 값 |
|---|---|
| 시간 (Andrew / Graham) | O(N log N) (정렬이 지배) |
| 시간 (정렬 후) | O(N) (스택 sweep) |
| 공간 | O(N) (결과 hull) |
| 안정성 | - (유일 결정) |
동일 점 (중복) 은 정렬 후 제거. Collinear (일직선) 점은 hull 에 포함할지 말지 선택.
변형 / 활용
1. Graham Scan
각도 정렬 (atan2) 후 같은 로직. Andrew 가 ssqrt 없고 실수 오차가 없어 더 선호됨.
2. Convex Hull Trick (CHT)
y = m*x + b 직선 중 특정 x 에서 최댓값. Convex hull (lower envelope) 과 동형.
3. 동적 Convex Hull
점이 추가/삭제될 때 hull 유지. O(log N) 갱신. (Overmars / Van Leeuwen 트리)
4. 3D Convex Hull
QuickHull O(N log N). 결과는 삼각형 메시 (face).
5. Rotating Calipers, 최근접 점 쌍, 최대 면적 삼각형
hull 위에서 O(N) 으로 각종 최적화.
함정
1. Collinear 처리
ccw <= 0 조건으로 collinear 점을 pop 하면 hull 변 가장자리 위의 점이 제외됨. 모든 collinear 점을 포함하려면 ccw < 0.
2. x 정렬만으로는 부족
x 가 같으면 y 정렬 필수. 안 하면 vertical line 에서 잘못된 hull.
3. Integer overflow
좌표 ±10^9 에서 (b.x - a.x) * (c.y - a.y) 는 ±4*10^18 까지 가능 -> C++ long long (64-bit). __int128 이 필요할 수 있음.
4. 점이 2개 이하
N ≤ 2 면 hull = 점들 그대로.
BOJ 연습 문제
| 번호 | 제목 | 정답률 | 링크 |
|---|---|---|---|
| BOJ 4181 | Convex Hull | 21.1% | kokoa-lab |
| BOJ 3679 | 단순 다각형 | 26.2% | kokoa-lab |
| BOJ 17058 | Convex Hull 연습 | 39.1% | kokoa-lab |
| BOJ 6850 | Cows | 42.5% | kokoa-lab |
| BOJ 2254 | 감옥 건설 | 33.1% | kokoa-lab |
참고
이 글의 용어 (4개)
- 기하 (Geometry) 기본algorithm
- 정의 Computational Geometry 는 점, 선, 다각형 등 기하 객체를 컴퓨터로 처리하는 알고리즘 분야. PS 에서는 2D 평면 위의 정수 좌표 가 주로 다루어지며,…
- 회전 캘리퍼스 (Rotating Calipers)algorithm
- 정의 회전 캘리퍼스 (Rotating Calipers) 는 볼록 다각형 위에서 서로 마주보는 두 평행선 (겹지름, antipodal pair) 을 회전시키며 다각형의 최장 거리,…
- CHT (Convex Hull Trick)algorithm
- 정의 Convex Hull Trick (CHT) 은 DP 전이 같이 선형식들의 lower envelope (또는 upper envelope) 에서 한 점 값을 평가하는 패턴을, …
- Geometry Basic: 벡터, CCW, 외적, 내적algorithm
- 정의 기하 알고리즘의 밑바탕. 대부분의 2D/3D 기하 문제는 벡터 연산, 내적/외적, CCW 판정 세 가지의 조합으로 풀립니다. 벡터 2D 벡터: 두 점 $A = (ax, ay…
이 개념을 다룬 위키 페이지 (14)
- wiki각도 정렬 (Angle Sorting)
- wikiConvex Hull 3D: 3차원 볼록 껍질
- wiki도형 불 연산 (Geometric Boolean Operations)
- wiki기하 (Geometry) 기본
- wikiGeometry Basic: 벡터, CCW, 외적, 내적
- wiki4차원 이상 기하 (Hyper Geometry)
- wikiHalf-Plane Intersection
- wiki선분 교차 (Line Segment Intersection)
- wiki최소 외접원 (Minimum Enclosing Circle)
- wiki평면 그래프 (Planar Graph)
- wiki볼록 다각형 내부 점 판정 (Point in Convex Polygon)
- wiki(오목 포함) 다각형 내부 점 판정 (Point in Polygon)
- wiki다각형 넓이 (Polygon Area)
- wiki회전 캘리퍼스 (Rotating Calipers)
💬 댓글