다각형 넓이 (Polygon Area)
정의
다각형 넓이 (Polygon Area) 는 2D 평면 위 단순다각형 (non-self-intersecting polygon) 의 면적을 신발끈 공식 (Shoelace Formula) 으로 O(N) 에 계산하는 알고리즘.
문제 상황과 동기
다각형의 넓이는 기하 문제에서 가장 빈번하게 등장하는 연산.
- Naive: 삼각형 분할 후 각각 넓이 합산. O(N) 이지만 구현이 번거롭고 분할 방식을 결정해야 함.
- Shoelace: 각 변의 기여도를 외적 하나로 계산. O(N) 에 통일된 공식.
핵심 통찰: 다각형의 부호 있는 넓이는 각 변 (i, i+1) 의 외적의 합의 절반. 즉 0.5 * | sum (x_i * y_{i+1} - x_{i+1} * y_i) |.
이 공식은 다각형이 볼록인지 오목인지, 시계/반시계 방향인지 관계없이 항상 성립.
시각화
핵심 아이디어
다각형의 꼭짓점을 P[0], P[1], ..., P[N-1] (반시계 또는 시계). 각 변 P[i] -> P[i+1] 에 대해, 사다리꼴의 부호 있는 넓이 를 더한다.
S = 0
for i in 0..N-1:
j = (i + 1) % N
S += P[i].x * P[j].y
S -= P[j].x * P[i].y
area = abs(S) / 2
이론적 근거: 그린 정리 (Green’s theorem) 의 이산 버전. 각 변의 사다리꼴 넓이가 모두 더해지면 내부는 중첩되고 외부는 상쇄됨.
부호: S > 0 이면 반시계 방향, S < 0 이면 시계 방향.
알고리즘
polygon_area(P[0..N-1]):
sum = 0
for i = 0 to N-1:
j = (i + 1) % N
sum += P[i].x * P[j].y
sum -= P[j].x * P[i].y
return abs(sum) / 2.0
구현
// Polygon area (shoelace), O(N)
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
struct Point { ll x, y; };
double polygon_area(vector<Point>& p) {
ll sum = 0;
int n = p.size();
for (int i = 0; i < n; i++) {
int j = (i + 1) % n;
sum += p[i].x * p[j].y;
sum -= p[j].x * p[i].y;
}
return abs(sum) / 2.0;
}
int main() {
vector<Point> poly = {{0,0}, {4,0}, {5,2}, {2,5}, {-1,2}};
cout << fixed << setprecision(1) << polygon_area(poly) << "\n";
vector<Point> tri = {{0,0}, {3,0}, {0,4}};
cout << fixed << setprecision(1) << polygon_area(tri) << "\n";
}19.0
6.0복잡도
| 항목 | 값 |
|---|---|
| 시간 | O(N) (N = 꼭짓점 수) |
| 공간 | O(1) 추가 (입력 배열 제외) |
변형 / 활용
1. 볼록다각형 여부 (방향 일관성)
Shoelace 의 sum 부호로 다각형이 반시계(양수)인지 시계(음수)인지 판별. 모든 연속 세 점의 CCW 가 방향과 일치하는지 확인.
2. 다각형의 무게 중심
면적으로 가중치를 준 꼭짓점 평균으로 centroid 계산 가능.
cx = sum((x_i + x_{i+1}) * (x_i*y_{i+1} - x_{i+1}*y_i)) / (6 * area)
cy = sum((y_i + y_{i+1}) * (x_i*y_{i+1} - x_{i+1}*y_i)) / (6 * area)
3. 오목 다각형에서도 동작
Shoelace 는 내부 영역의 중첩과 상쇄가 자동으로 처리되므로 오목 다각형에서도 올바른 값.
4. 정수 좌표 + long long
좌표가 정수이면 넓이는 .0 또는 .5. 정수 배율 결과가 필요하면 abs(sum) 반환 후 따로 2 로 나누기.
함정
1. 오버플로우
x_i * y_j 가 10^6 * 10^6 = 10^12. N=10^5 면 sum 은 10^17 까지 가능. C++ long long (9e18) 은 OK, int 는 무조건 overflow.
2. 다각형 방향
입력이 시계(cw)인지 반시계(ccw)인지 모를 수 있음. abs(sum) 으로 절대값 처리.
3. 마지막 변
i=N-1 일 때 j=0 으로 돌아오는 것 ((i+1) % N) 이 중요. 열린 폴리라인이 아닌 닫힌 다각형이어야 함.
4. 정수 나눗셈
C++ 에서 abs(sum) / 2 는 정수 나눗셈. 2.0 으로 나누거나 (double) 캐스팅 필요.
BOJ 연습 문제
| 번호 | 제목 | 정답률 | 링크 |
|---|---|---|---|
| BOJ 2166 | 다각형의 면적 | 39.5% | kokoa-lab |
| BOJ 2477 | 참외밭 | 44.5% | kokoa-lab |
| BOJ 1004 | 어린 왕자 | 33.2% | kokoa-lab |
| BOJ 1709 | (관련: 원의 넓이) | (수집 안 됨) | kokoa-lab |
참고
- CCW (외적의 기초)
- Convex Hull (볼록 껍질에서도 같은 공식)
- Geometry (기하 기본)
이 글의 용어 (3개)
- 기하 (Geometry) 기본algorithm
- 정의 Computational Geometry 는 점, 선, 다각형 등 기하 객체를 컴퓨터로 처리하는 알고리즘 분야. PS 에서는 2D 평면 위의 정수 좌표 가 주로 다루어지며,…
- 볼록 껍질 (Convex Hull)algorithm
- 정의 볼록 껍질 (Convex Hull) 은 주어진 점 집합 P 를 모두 포함하는 최소 크기의 볼록 다각형. 즉 P 의 어떤 점도 다각형 외부에 있지 않고, 다각형의 꼭짓점은 P…
- Geometry Basic: 벡터, CCW, 외적, 내적algorithm
- 정의 기하 알고리즘의 밑바탕. 대부분의 2D/3D 기하 문제는 벡터 연산, 내적/외적, CCW 판정 세 가지의 조합으로 풀립니다. 벡터 2D 벡터: 두 점 $A = (ax, ay…
💬 댓글