题意: 给出平面上的n个点,找出一条直线,使得所有的点都在直线的同一侧或者在直线上,且所有的点到直线的距离最小.
意解: 要求点在线的同一侧,则直线不能够穿过凸包,而且线在凸包的边上时能达到最优解,至于为什么凸包能保证最优解,自己画画图就明白了.
预处理x,y,然后直接套凸包模板就行了,不过要注意只有一个点的情况,因为这个wa了几次了;
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#define exp 1e-10
using namespace std;
int sumx,sumy;
struct Point
{
double x,y;
Point(double x0 = 0, double y0 = 0)
{
x = x0;
y = y0;
}
bool operator < (const Point &ant) const
{
if(ant.x != x) return ant.x > x;
return ant.y > y;
}
};
Point operator - (Point A, Point B)
{
return Point(A.x - B.x , A.y - B.y);
}
double cross(Point A,Point B)
{
return A.x * B.y - A.y * B.x;
}
double dcmp(double x)
{
return x >= 0? x : -x;
}
class Convex
{
public:
int convex(Point *p, int n, Point *ch)
{
int m = 0;
//sort(p, p + n);
for(int i = 0; i < n; i++)
{
while(m > 1 && cross(ch[m - 1] - ch[m - 2],p[i] - ch[m - 2]) <= exp) m--;
ch[m++] = p[i];
}
int k = m;
for(int i = n - 2; i >= 0; i--)
{
while(m > k && cross(ch[m - 1] - ch[m - 2],p[i] - ch[m - 2]) <= exp) m--;
ch[m++] = p[i];
}
if(n > 1) m--;
return m;
}
} hull;
int main()
{
//freopen("in.txt","r",stdin);
int T,n,cnt = 0;
scanf("%d",&T);
while(T--)
{
Point p[11000],ch[11000];
sumx = sumy = 0;
printf("Case #%d: ",++cnt);
scanf("%d",&n);
for(int i = 0; i < n; i++)
{
scanf("%lf %lf",&p[i].x,&p[i].y);
sumx += p[i].x;
sumy += p[i].y;
}
sort(p,p + n);
int m = 1;
for(int i = 1; i < n; i++)
{
if(p[i].x == p[i - 1].x && p[i].y == p[i - 1].y) continue;
else p[m++] = p[i];
}
int ans = hull.convex(p,m,ch);
double a,b,c;
double res = 9999999999.0;
//sort(ch, ch + ans);
ch[ans] = ch[0];
for(int i = 0; i < ans; i++)
{
a = ch[i + 1].y - ch[i].y;
b = ch[i].x - ch[i + 1].x;
c = ch[i].y * ch[i + 1].x - ch[i].x * ch[i + 1].y;
double sum = (n - 2) * c + (sumx - ch[i].x - ch[i + 1].x) * a + (sumy - ch[i].y - ch[i + 1].y) * b;
double sum1 = sum / sqrt(a * a * 1.0 + b * b * 1.0);
if(dcmp(sum1) < res) res = dcmp(sum1);
}
if(n == 1) puts("0.000");
else printf("%.3lf\n",res /(double)n);
}
return 0;
}