二维凸包板子题, 借此学习了 \(Andrew\) 算法, 可以在 \(O(n \log n)\) 的时间内求出凸包.
\(code:\)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read() {
int x = 0, f = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
return x * f;
}
const int N = 1e5 + 5;
int stk[N], top, num;
bool used[N];
struct Vec {
double x, y;
bool operator < (const Vec &a) const {
if (x == a.x) return y < a.y;
return x < a.x;
}
Vec operator - (const Vec &a) const {
return (Vec){x - a.x, y - a.y};
}
double operator * (const Vec &a) const {
return x * a.y - a.x * y;
}
double d(Vec a) {
return sqrt((x - a.x) * (x - a.x) + (y - a.y) * (y - a.y));
}
} p[N], h[N];
bool Check(Vec a, Vec b, Vec c) {
return (a - b) * (c - a) <= 0;
}
void Andrew(int n) {
sort(p + 1, p + n + 1);
stk[++top] = 1;
for (int i = 2; i <= n; i++) {
while (top >= 2 && Check(p[stk[top]], p[stk[top - 1]], p[i])) used[stk[top--]] = 0;
used[i] = 1, stk[++top] = i;
}
int tmp = top;
for (int i = n - 1; i > 0; i--) {
if (!used[i]) {
while (top > tmp && Check(p[stk[top]], p[stk[top - 1]], p[i])) used[stk[top--]] = 0;
used[i] = 1, stk[++top] = i;
}
}
for (int i = 1; i <= top; i++) h[i] = p[stk[i]];
num = top - 1;
}
int n;
double ans;
int main() {
n = read();
for (int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
Andrew(n);
for (int i = 1; i <= num; i++) ans += h[i].d(h[i + 1]);
printf("%.2lf", ans);
return 0;
}