题意:有n个点,找一条直线,让所有点都在直线的同一侧(也可在直线上),且到直线的距离之和最小。输出距离和与点数的比值。
题解:所有点在直线同侧,也就是直线不能穿过凸包,那么凸包的边所在直线就是可能的解,点(x0,y0)到直线(Ax + By + C = 0)的距离
dis = |Ax0 + By0 + C| / sqrt(A^2 + B^2)
把凸包的每个边拿去计算,所有点到其的距离和,根据计算式,先把所有点的x坐标之和和y坐标之和计算出来减少时间复杂度。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const double PI = acos(-1);
const int N = 10005;
const double INF = 1e9;
struct Point {
    double x, y;
    Point(double x = 0, double y = 0): x(x), y(y) {}
}P[N], res[N];
struct Circle {
    Point c;
    double r;
    Circle() {}
    Circle(Point c, double r = 0): c(c), r(r) {}
    Point point(double a) {
        return Point(c.x + cos(a) * r, c.y + sin(a) * c.y);
    }
};
int n;
double Sqr(double x) {
    return x * x;
}
Point operator + (Point A, Point B) {
    return Point(A.x + B.x, A.y + B.y);
}
Point operator - (Point A, Point B) {
    return Point(A.x - B.x, A.y - B.y);
}
Point operator * (Point A, double p) {
    return Point(A.x * p, A.y * p);
}
Point operator / (Point A, double p) {
    return Point(A.x / p, A.y / p);
}
//计算点积的正负  负值夹角为钝角
int dcmp(double x) {
    if (fabs(x) < 1e-9)
        return 0;
    return x < 0 ? -1 : 1;
}
bool operator < (const Point& a, const Point& b) {
    return a.x < b.x || (a.x == b.x && a.y < b.y);
}
bool operator == (const Point& a, const Point& b) {
    return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
}
//计算点积
double Dot(Point A, Point B) {
    return A.x * B.x + A.y * B.y;
}
//计算叉积,也就是数量积
double Cross(Point A, Point B) {
    return A.x * B.y - A.y * B.x;
}
//计算向量长度
double Length(Point A) {
    return sqrt(Dot(A, A));
}
//向量A旋转rad弧度,rad负值为顺时针旋转
Point Rotate(Point A, double rad) {
    return Point(A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + A.y * cos(rad));
}
//角度转化弧度
double torad(double deg) {
    return deg / 180.0 * PI;
}
int ConvexHull(Point* P, int& cnt, Point* res) {
    sort(P, P + cnt);
    cnt = unique(P, P + cnt) - P;
    int m = 0;
    for (int i = 0; i < cnt; i++) {
        while (m > 1 && Cross(res[m - 1] - res[m - 2], P[i] - res[m - 2]) <= 0)
            m--;
        res[m++] = P[i];
    }
    int k = m;
    for (int i = cnt - 2; i >= 0; i--) {
        while (m > k && Cross(res[m - 1] - res[m - 2], P[i] - res[m - 2]) <= 0)
            m--;
        res[m++] = P[i];
    }
    if (cnt > 1)
        m--;
    return m;
}

void change(double &A, double &B, double &C, Point a, Point b) {
    A = b.y - a.y;
    B = a.x - b.x;
    C = b.x * a.y - a.x * b.y;
}

int main() {
    int t, cas = 1;
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        double sumx = 0, sumy = 0;
        for (int i = 0; i < n; i++) {
            scanf("%lf%lf", &P[i].x, &P[i].y);
            sumx += P[i].x;
            sumy += P[i].y;
        }
        if (n <= 2) {
            printf("Case #%d: 0.000\n", cas++);
            continue;
        }
        int temp = ConvexHull(P, n, res);
        double minn = INF;
        for (int i = 0; i < temp; i++) {
            double A, B, C;
            change(A, B, C, res[i], res[(i + 1) % temp]);
            double sumdis = fabs(A * sumx + B * sumy + C * n) / sqrt(Sqr(A) + Sqr(B));
            minn = min(minn, sumdis);
        }
        printf("Case #%d: %.3lf\n", cas++, minn / n);
    }
    return 0;
}