UVA11168 Airport
UVA11168 Airport
题意
平面上有\(n\)个点,求一条直线,使得这\(n\)个点都在这条直线上或同侧,且每个点到该直线的距离的平均值尽量小。求最小的平均值。有\(T\)组数据。
\(T \leq 65,1\leq n\leq {10}^{4}\) , \(|x|,|y|\leq 8*{10}^{4}\) 。
题解
显然这条线与\(n\)个点的凸包是贴着的,不然肯定能更加靠近这个凸包使距离总和更小。
然后就是枚举凸包上的边作为这条直线。然而如果对每个点算距离会超时。
考虑点到直线的距离公式\(d\) \(=\) \(\frac{|Ax + By + C|}{\sqrt{A^2+B^2} }\) 。
同一条直线分母相同,由于点都在线的同一边,分子绝对值中的正负情况也是相同的。
只用算出直线的\(A,B,C\)和所有点的横纵坐标和就能快速算出一条线的答案了。
注意只有一个点是要特判。
\(Code\)
#include <bits/stdc++.h>
#define LL long long
#define LD long double
using namespace std;
const int N=3e5+10;
const LL INF=1e16;
LD ans;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void print(LL x){
if(x>9) print(x/10);
putchar(x%10+'0');
}
int n;
struct P{
int x,y;
P(int xx=0,int yy=0){x=xx;y=yy;}
}p[N];
P operator - (P x,P y){
return P(x.x-y.x,x.y-y.y);
}
P operator + (P x,P y){
return P(x.x+y.x,x.y+y.y);
}
LL cha(P x,P y){
return (LL)x.x*y.y-(LL)x.y*y.x;
}
bool cmp(P x,P y){
if(x.x!=y.x) return x.x<y.x;
else return x.y<y.y;
}
int tp;
int q[N];
LL sx,sy;
LD sol(P x,P y){
LD A,B,C;
if(x.x==y.x){
A=1;B=0;C=-x.x;
}
else if(x.y==y.y){
A=0;B=1;C=-x.y;
}
else{
B=-1;
A=(LD)(x.y-y.y)/(LD)(x.x-y.x);
C=(LD)x.y-A*(LD)x.x;
}
LD re=(LD)1/(LD)sqrt(A*A+B*B);
re=re*(A*(LD)sx+B*(LD)sy+(LD)n*C);
if(re<0) re=-re;
return re;
}
int main(){
int T;scanf("%d",&T);
for(int tt=1;tt<=T;++tt){
scanf("%d",&n);
sx=0;sy=0;
for(int i=1;i<=n;++i){
scanf("%d%d",&p[i].x,&p[i].y);
sx+=p[i].x;sy+=p[i].y;
}
if(n==1){
ans=0;
printf("Case #%d: %0.3Lf\n",tt,ans);
continue;
}
sort(p+1,p+1+n,cmp);
ans=INF;
tp=0;
for(int i=1;i<=n;++i){
while(tp>=2&&cha(p[q[tp]]-p[q[tp-1]],p[i]-p[q[tp-1]])>=0) --tp;
q[++tp]=i;
}
for(int i=1;i<tp;++i){
ans=min(ans,sol(p[q[i]],p[q[i+1]]));
}
tp=0;
for(int i=n;i>=1;--i){
while(tp>=2&&cha(p[q[tp]]-p[q[tp-1]],p[i]-p[q[tp-1]])>=0) --tp;
q[++tp]=i;
}
for(int i=1;i<tp;++i){
ans=min(ans,sol(p[q[i]],p[q[i+1]]));
}
ans=ans/(LD)n;
printf("Case #%d: %0.3Lf\n",tt,ans);
}
return 0;
}