题意:给出平面上的n个点,求一条直线,使得所有点在该直线的同一侧且所有点到该直线的距离和最小,输出该距离和。
思路:要使所有点在该直线的同一侧,明显是直接利用凸包的边更优。所以枚举凸包的没条边,然后求距离和。直线一般式为Ax + By + C = 0.点(x0, y0)到直线的距离为
fabs(Ax0+By0+C)/sqrt(A*A+B*B).由于所有点在直线的同一侧,那么对于所有点,他们的(Ax0+By0+C)符号相同,显然可以累加出sumX和sumY,然后统一求和。
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define INF 800000000 8 int sumX, sumY, N; 9 struct Point{int x, y;}; 10 Point p[10002], ch[10002]; 11 bool cmp(Point a, Point b){ 12 return a.x == b.x ? a.y < b.y : a.x < b.x; 13 } 14 int Cross(Point a, Point b, Point c){ 15 return (a.x-c.x)*(b.y-c.y) - (a.y-c.y)*(b.x-c.x); 16 } 17 const double eps = 1e-10; 18 int Dcmp(double x){ 19 if(x < eps)return 0; 20 return x < 0 ? -1 : 1; 21 } 22 int ConvexHull()//凸包 23 { 24 sort(p, p+N, cmp); 25 int m = 0; 26 for(int i = 0; i < N; i++){ 27 while(m > 1 && Dcmp(Cross(ch[m-1], p[i], ch[m-2])) <= 0)m--; 28 ch[m++] = p[i]; 29 } 30 int k = m; 31 for(int i = N-2; i >= 0; i--){ 32 while(m > k && Dcmp(Cross(ch[m-1], p[i], ch[m-2])) <= 0)m--; 33 ch[m++] = p[i]; 34 } 35 if(N > 1)m--; 36 return m; 37 } 38 double getDist(Point a, Point b){ 39 double A, B, C, k, v; 40 A = a.y - b.y; 41 B = b.x - a.x; 42 C = a.x*b.y - a.y*b.x; 43 k = fabs(A*sumX + B*sumY + N * C); 44 v = sqrt(A * A + B * B); 45 return k / v; 46 } 47 double Line(int m) 48 { 49 double minL = INF*1.0, L; 50 for(int i = 0; i < m; i++){ 51 L = getDist(ch[i], ch[(i+1)%m]);//得到所有点到凸包一条边的距离 52 minL = min(minL, L); 53 } 54 return minL; 55 } 56 int main() 57 { 58 int i, j, t; 59 cin>>t; 60 int cas = 1; 61 while(t--) 62 { 63 cin>>N; 64 sumX = sumY = 0; 65 for(i = 0; i < N; i++){ 66 scanf("%d%d", &p[i].x, &p[i].y); 67 sumX += p[i].x; 68 sumY += p[i].y; 69 } 70 printf("Case #%d: ", cas++); 71 if(N == 1 || N== 2){ 72 printf("0.000 "); 73 continue; 74 } 75 printf("%.3lf ", Line( ConvexHull() ) / (N*1.0)); 76 } 77 return 0; 78 }