Convex Hull (볼록 껍질) 정의

알고리즘

Convex Hull 알고리즘을 배우기 위한 벡터의 외적과 CCW

img1

이때, 우리가 아래에서 사용하는 알고리즘은 평면상에서 convex hull을 구하는 알고리즘입니다.

  • 따라서, m3와 n3라는 z성분 값을 0으로 만들어서 식을 재정리할 수 있습니다.
    • 벡터 u x 벡터 v = (0, 0, m1n2 - m2n1)

img2

struct Point {
	int x, y;
};
ll ccw(const Point a, const Point b, const Point c) {
	return (1LL * a.x * b.y + 1LL * b.x * c.y + 1LL * c.x * a.y) - (1LL * b.x * a.y + 1LL * c.x * b.y + 1LL * a.x * c.y);
}

Andrew’s Algorithm

img3

img4

img5

img6

img7

img8

img9

img10

img11

img12

복잡도

구현

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#define endl '\n'
#define rep(i, a, b) for(int i=(a);i<(b); i++)
#define r_rep(i,a,b) for(int i=(a);i>(b); i--)
typedef long long ll;
struct Point {
	int x, y;
	int px, py;
};
const int MAXN = 100000 + 100;
using namespace std;

int n;
Point point[MAXN];
int rear;
int stk[MAXN];
void input() {
	cin >> n;
	rep(i, 0, n) {
		cin >> point[i].x >> point[i].y;
		point[i].px = 1, point[i].py = 0;
	}
}
bool comp(const Point a, const Point b) {
	if (1LL * a.py * b.px != 1LL * a.px * b.py)
		return 1LL * a.py * b.px < 1LL * a.px * b.py;
	if (a.y != b.y)
		return a.y < b.y;
	return a.x < b.x;
}
ll ccw(const Point a, const Point b, const Point c) {
	return (1LL * a.x * b.y + 1LL * b.x * c.y + 1LL * c.x * a.y) - (1LL * b.x * a.y + 1LL * c.x * b.y + 1LL * a.x * c.y);
}
void solve() {
	rear = 0;
	stk[rear++] = 0;
	stk[rear++] = 1;
	int next = 2;
	while (next < n) {
		while (rear >= 2) {
			int second = stk[--rear];
			int first = stk[rear - 1];
			if (ccw(point[first], point[second], point[next]) > 0) {
				stk[rear++] = second;
				break;
			}
		}
		stk[rear++] = next++;
	}
}
template <typename It>
void _swap(It &a, It &b) {
	It c(a); a = b; b = c;
}
template <typename It, typename Comp>
void _sort(It begin, It end, Comp comp) {
	if (begin == end)
		return;
	_swap(*begin, *((end - begin) / 2 + begin));
	It pi = begin;
	It le = begin + 1;
	It ri = end - 1;
	while (le <= ri) {
		while (le <= ri && !comp(*pi, *le))
			le++;
		while (le <= ri && !comp(*ri, *pi))
			ri--;
		if (le <= ri)
			_swap(*le, *ri);
	}
	_swap(*pi, *ri);
	_sort(begin, ri, comp);
	_sort(ri + 1, end, comp);
}

void process() {
	input();
	_sort(point, point + n, comp);
	rep(i, 1, n) {
		point[i].px = point[i].x - point[0].x;
		point[i].py = point[i].y - point[0].y;
	}
	_sort(point + 1, point + n, comp);
	solve();
	cout << rear << endl;
}
int main() {
	int tc; cin >> tc;
	for (int rnd = 1; rnd <= tc; rnd++) {
		cout << "#" << rnd << " ";
		process();
	}
	return 0;
}