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;
}
posted @ 2020-10-05 19:12  Iscream-2001  阅读(137)  评论(0编辑  收藏  举报
/* */ /* */