UVa 11168(凸包、直线一般式)

要点

  • 找凸包上的线很显然
  • 但每条线所有点都求一遍显然不可行,优化方法是:所有点都在一侧所以可以使用直线一般式的距离公式\(\frac{|A* \sum{x}+B* \sum{y}+C*n|}{\sqrt {A^2+B^2}}\)\(O(1)\)算出总距离
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

typedef double db;
const int maxn = 1e4 + 5;
const db eps = 1e-8;

int dcmp(db x) {
	if (fabs(x) < eps)	return 0;
	return x > 0 ? 1 : -1;
}

int T, n, cnt;
struct Point {
	db x, y;
	
	Point(){}

	Point(db a, db b):x(a), y(b){}

	bool operator < (const Point &rhs) const {
		if (dcmp(x - rhs.x) != 0)	return dcmp(x - rhs.x) < 0;
		return dcmp(y - rhs.y) < 0;
	}
}p[maxn];
Point v[maxn];

db Cross(Point A, Point B) {//顺时针转动则叉积为负
	return A.x * B.y - A.y * B.x;
}

Point operator - (Point A, Point B) {
	return Point(A.x - B.x, A.y - B.y);
}

bool operator == (Point A, Point B) {
	return dcmp(A.x - B.x) == 0 && dcmp(A.y - B.y) == 0;
}

void ConvexHull(int n) {
	cnt = 0;
	sort(p, p + n);
	n = unique(p, p + n) - p;//去重

	for (int i = 0; i < n; i++) {
		while (cnt > 1 && dcmp(Cross(v[cnt - 1] - v[cnt - 2], p[i] - v[cnt - 2])) <= 0)	cnt--;
		v[cnt++] = p[i];
	}
	int k = cnt;
	for (int i = n - 2; ~i; --i) {
		while (cnt > k && dcmp(Cross(v[cnt - 1] - v[cnt - 2], p[i] - v[cnt - 2])) <= 0)	cnt--;
		v[cnt++] = p[i];
	}
	if (n > 1)	cnt--;
}

db Solve() {
	if (n == 1)	return 0;//特判
	db res = 1e18, X = 0, Y = 0;

	for (int i = 0; i < n; i++) {
		X += p[i].x;
		Y += p[i].y;
	}
	for (int i = 0; i < cnt; i++) {
		Point a = v[i], b = v[(i + 1) % cnt];
		db A = b.y - a.y, B = a.x - b.x, C = Cross(b, a);
		db calc = fabs((A * X + B * Y + C * n) / sqrt(A * A + B * B));
		if (dcmp(calc - res) < 0) {
			res = calc;
		}
	}

	return res / n;
}

int main() {
	scanf("%d", &T);
	for (int kase = 1; kase <= T; kase++) {
		scanf("%d", &n);
		for (int i = 0; i < n; i++)
			scanf("%lf %lf", &p[i].x, &p[i].y);

		ConvexHull(n);//求凸包
		printf("Case #%d: %.3lf\n", kase, Solve());
	}
}
posted @ 2019-06-01 23:52  AlphaWA  阅读(163)  评论(0编辑  收藏  举报