青衣 发表于 2021-7-17 11:59:25

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;
Point v;

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 - v, p - v)) <= 0)cnt--;
v = p;
}
int k = cnt;
for (int i = n - 2; ~i; --i) {
while (cnt > k && dcmp(Cross(v - v, p - v)) <= 0)cnt--;
v = p;
}
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.x;
Y += p.y;
}
for (int i = 0; i < cnt; i++) {
Point a = v, 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.x, &p.y);

ConvexHull(n);//求凸包
printf("Case #%d: %.3lf\n", kase, Solve());
}
}



文档来源:51CTO技术博客https://blog.51cto.com/u_14696602/3107446
页: [1]
查看完整版本: UVa 11168(凸包、直线一般式)