[USACO5.1] Fencing the Cows

二维凸包板子题, 借此学习了 \(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;
}
看不见我看不见我看不见我