Airport Uva11168 凸包

AirPort,Uva 11168

题意:

给出n个点,找一条直线,使得所有的点在直线的一侧(或者在直线上),并且所有的点到直线距离的平均最小。

解题:

对于所有的点我们先建立凸包,直觉可以发现直线在凸包上回会比和凸包相离要合适。所以依次枚举出所有的凸包边。事先计算出全部的点的坐标和,可以在更短的时间内求得全部点到直线的距离,因为所有的点在直线同一侧,所以 Ax0+By0+C A x 0 + B y 0 + C 具有相同的正负性。通过点到直线的距离公式就可以计算出来。

|Axsum+Bysum+nC|A2+B2 | A x s u m + B y s u m + n C | A 2 + B 2

#include <bits/stdc++.h>

using namespace std;
struct Point{
    double x,y;
    Point(double x,double y):x(x),y(y){}
    Point(){}
};
typedef Point Vector;
Point operator+(Point a,Point b){return Point(a.x+b.x,a.y+b.y);}
Point operator-(Point a,Point b){return Point(a.x-b.x,a.y-b.y);}
Point operator*(Point a,double D){return Point(a.x*D,a.y*D);}
Point operator/(Point a,double D){return Point(a.x/D,a.y/D);}
bool operator < (const Point &a, const Point & b){return a.x < b.x || (a.x == b.x && a.y < b.y);}
const double eps=1e-10;
int dcmp(double x){if(fabs(x)<eps) return 0; else return x<0?-1:1;}
bool operator==(const Point& a,const Point& b){return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;}
double dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}
double length(Vector a){return sqrt(dot(a,a));}
double angle(Vector a,Vector b){return acos( dot(a,b)/length(a)/length(b) );}
double angle(Vector a){return atan2(a.y,a.x);}
double cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;}
double area2(Point A,Point B,Point C){return cross(B-A,C-A);}
Vector rotate(Vector a,double rad){
  return Vector(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad));
}
Vector normal(Vector a){double l=length(a);return Vector(-a.y/l,a.x/l);}
double torad(double deg){return deg/180 * M_PI;}

double distanceToLine(Point P,Point A,Point B)
{
    Vector v1=B-A,v2=P-A;
    return fabs(cross(v1,v2))/length(v1);
}

int convexHull(Point *p,int n,Point* ch) {
  sort(p,p+n);
  int m=0;
  for(int i=0;i<n;i++){
    while(m>1&&dcmp(cross(ch[m-1]-ch[m-2],p[i]-ch[m-2] ))<=0 )m--;
    ch[m++]=p[i];
  }
  int k=m;
  for(int i=n-2;i>=0;i--) {
    while(m>k&&dcmp(cross(ch[m-1]-ch[m-2],p[i]-ch[m-2]))<=0)m--;
    ch[m++]=p[i];
  }
  if(n>1)m--;
  return m;
}
double sumx,sumy;
double calDistanceSum(int n,Point p1,Point p2){
    double x1,y1,x2,y2;
    x1=p1.x;y1=p1.y;
    x2=p2.x;y2=p2.y;
    double A=y2-y1,B=x1-x2,C=x2*y1-x1*y2;
    double sum = fabs(A*sumx+B*sumy+n*C)/sqrt(A*A+B*B);
    return sum;
}
const int maxn = 1e4+10;
Point P[maxn],ch[maxn];

int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--) {
        int n;
        scanf("%d",&n);
        sumx=0,sumy=0;
        for(int i=0;i<n;i++) {
            scanf("%lf%lf",&P[i].x,&P[i].y);
            sumx+=P[i].x;sumy+=P[i].y;
        }
        if(n<=2){printf("Case #%d: 0.000\n",cas++);continue;}
        int m=convexHull(P,n,ch);
        double mindis=0x3f3f3f3f,dis;
        for(int i=0;i<m;i++) {
            dis=calDistanceSum(n,ch[i],ch[(i+1)%m]);
            mindis=dis<mindis?dis:mindis;
        }
        printf("Case #%d: %.3lf\n",cas++,mindis/n);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值