题意:有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;
}