TIOJ-1178

給定平面上N個點,請計算出凸包上的頂點數。所謂的凸包,就是指一個包含所有點的最小凸多邊形。
所謂凸包上的頂點,指的是轉折處(邊上的點不算)。

$1\leq N\leq 10,000$

點的座標皆在int範圍


凸包裸題
用Andrew’s Monotone Chain來實作
複雜度$\mathcal{O}(NlogN)$

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
#include<bits/stdc++.h>
using namespace std;

long long cross(pair<long long,long long> &a, pair<long long,long long> &b, pair<long long,long long> &c) {
return (b.first-a.first) * (c.second - a.second) - (b.second - a.second) * (c.first - a.first);
}//ab外積ac ab到ac為逆時針旋轉時外積為正 反則負 共線為0

signed main() {
ios::sync_with_stdio(0); cin.tie(0);

int n;
cin >> n;
vector<pair<long long,long long>> arr(n), dn, up;//點 下凸包 上凸包
for(int i = 0; i < n; i++)
cin >> arr[i].first >> arr[i].second;
sort(arr.begin(), arr.end());//照座標排序

for(int i = 0; i < n; i++) {
while(dn.size() >= 2 && cross(dn[dn.size()-2], dn.back(), arr[i]) <= 0)
dn.pop_back();
while(up.size() >= 2 && cross(up[up.size()-2], up.back(), arr[i]) >= 0)
up.pop_back();
dn.push_back(arr[i]);
up.push_back(arr[i]);
}//單調隊列

for(int i = int(up.size())-2; i > 0; i--)
dn.push_back(up[i]);
//把上凸包的中間元素以反方向push進下凸包(前後兩點為起終點 重複)
cout << dn.size();

return 0;
}