题意:
平面上有n个点,求一条直线使得所有点都在直线的同一侧。并求这些点到直线的距离之和的最小值。
分析:
只要直线不穿过凸包,就满足第一个条件。要使距离和最小,那直线一定在凸包的边上。所以求出凸包以后,枚举每个边求出所有点到直线的距离之和得到最小值。
点到直线距离公式为:
因为点都在直线同一侧,所以我们可以把加法“挪”到里面去,最后再求绝对值,所以可以预处理所有点的横坐标之和与纵坐标之和。当然常数C也要记得乘上n倍。
已知两点坐标求过该点直线的方程,这很好求不再赘述,考虑到直线没有斜率的情况,最终要把表达式中的分母乘过去。
1 //#define LOCAL 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 #include <vector> 7 using namespace std; 8 9 struct Point 10 { 11 double x, y; 12 Point(double x=0, double y=0):x(x), y(y) {} 13 }; 14 typedef Point Vector; 15 Point operator + (Point A, Point B) 16 { 17 return Point(A.x+B.x, A.y+B.y); 18 } 19 Point operator - (Point A, Point B) 20 { 21 return Point(A.x-B.x, A.y-B.y); 22 } 23 bool operator < (const Point& A, const Point& B) 24 { 25 return A.x < B.x || (A.x == B.x && A.y < B.y); 26 } 27 bool operator == (const Point& A, const Point& B) 28 { 29 return A.x == B.x && A.y == B.y; 30 } 31 double Cross(Vector A, Vector B) 32 { 33 return A.x*B.y - A.y*B.x; 34 } 35 36 vector<Point> ConvexHull(vector<Point> p) { 37 // 预处理,删除重复点 38 sort(p.begin(), p.end()); 39 p.erase(unique(p.begin(), p.end()), p.end()); 40 41 int n = p.size(); 42 int m = 0; 43 vector<Point> ch(n+1); 44 for(int i = 0; i < n; i++) { 45 while(m > 1 && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--; 46 ch[m++] = p[i]; 47 } 48 int k = m; 49 for(int i = n-2; i >= 0; i--) { 50 while(m > k && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--; 51 ch[m++] = p[i]; 52 } 53 if(n > 1) m--; 54 //for(int i = 0; i < m; ++i) printf("%lf %lf ", ch[i].x, ch[i].y); 55 ch.resize(m); 56 return ch; 57 } 58 59 double sumx, sumy; 60 61 double Dist(Point a, Point b, int m) 62 { 63 double A = a.y-b.y, B = b.x-a.x, C = a.x*b.y - b.x*a.y; 64 //printf("%lf %lf", fabs(A*sumx+B*sumy+C), sqrt(A*A+B*B)); 65 return (fabs(A*sumx+B*sumy+C*m) / sqrt(A*A+B*B)); 66 } 67 68 int main(void) 69 { 70 #ifdef LOCAL 71 freopen("11168in.txt", "r", stdin); 72 #endif 73 74 int T; 75 scanf("%d", &T); 76 for(int kase = 1; kase <= T; ++kase) 77 { 78 int n; 79 vector<Point> p; 80 sumx = 0.0, sumy = 0.0; 81 scanf("%d", &n); 82 for(int i = 0; i < n; ++i) 83 { 84 double x, y; 85 scanf("%lf%lf", &x, &y); 86 p.push_back(Point(x, y)); 87 sumx += x; sumy += y; 88 } 89 vector<Point> ch = ConvexHull(p); 90 int m = ch.size(); 91 //for(int i = 0; i < m; ++i) printf("%lf %lf ", ch[i].x, ch[i].y); 92 if(m <= 2) 93 { 94 printf("Case #%d: 0.000 ", kase); 95 continue; 96 } 97 98 double ans = 1e10; 99 for(int i = 0; i < m; ++i) 100 ans = min(ans, Dist(ch[i], ch[(i+1)%m], n)); 101 printf("Case #%d: %.3lf ", kase, ans/n); 102 } 103 }