UVA - 11168 Airport (凸包+整理模板)

Time Limit: 3000MS  64bit IO Format: %lld & %llu

 Status uDebug

Description

Download as PDF

题意:

给平面上n个点,找一条直线,使得所有点在直线同侧(或直线上),且到直线距离之和尽量小。

分析:

O(n)时间遍历凸包的n条边,计算每条边对应的总距离,比较哪一个最小。

计算总距离可通过点到直线的距离公式,计算所有点的x坐标与y坐标之和,O(1)的计算出总距离。

改了一下模板,统一了一下。

#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
const long long N=10005;
const long long mod=1e9;
const double eps=1e-10;
const double PI=acos(-1.0);
typedef long long ll;

struct Point {
    double x,y;
    Point (double x=0, double y=0):x(x),y(y) {}
};

typedef Point Vector;

Vector operator + (Vector A, Vector B) { return Vector(A.x+B.x, A.y+B.y);}
Vector operator - (Point A, Point B) { return Vector(A.x-B.x, A.y-B.y);}
Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p);}
Vector operator / (Vector A, double p) { return Vector(A.x/p, A.y/p);}

bool operator < (const Point &a, const Point &b) {
    return a.x<b.x|| (a.x==b.x && a.y<b.y);
}

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 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);}

//rad是弧度
Vector Rotate(Vector A, double rad) {
    return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
}

//计算向量的单位法线,调用前确保A不是零向量
Vector Normal(Vector A) {
    double L=Length(A);
    return Vector(-A.y/L, A.x/L);
}

//直线交点,确保P+tv和Q+tw有唯一交点。当且仅当Cross(v,w)非0
Point GetLineIntersection(Point P, Vector v, Point Q, Vector w) {
    Vector u=P-Q;
    double t=Cross(w, u)/Cross(v, w);
    return P+v*t;
}

//点到直线距离
double DistanceToLine(Point P, Point A, Point B) {
    Vector v1=B-A,v2=P-A;
    return fabs(Cross(v1, v2))/Length(v1);
}

//点到线段距离
double DistanceToSegment(Point P, Point A, Point B) {
    if (A==B) return Length(P-A);
    Vector v1=B-A, v2=P-A,v3=P-B;
    if (dcmp(Dot(v1, v2))<0) return Length(v2);
    else if (dcmp(Dot(v1, v3))>0) return Length(v3);
    else return fabs(Cross(v1, v2)) / Length(v1);
}

//计算点在线段上的投影
Point GetLineProjection(Point P, Point A, Point B) {
    Vector v=B-A;
    return A+v*(Dot(v, P-A)/Dot(v, v));
}

//线段相交判定(不计算端点)
bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2) {
    double c1=Cross(a2-a1, b1-a1), c2=Cross(a2-a1, b2-a1),
    c3=Cross(b2-b1, a1-b1), c4=Cross(b2-b1, a2-b1);
    return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
}

//计算端点是否在另外一条线段上
bool OnSegment(Point p, Point a1, Point a2) {
    return dcmp(Cross(a1-p, a2-p))==0 &&dcmp(Dot(a1-p, a2-p))<0;
}

//计算凸多边形面积
double ConvexPolyonArea(Point* p,int n) {
    double area=0;
    for (int i=1; i<n-1; i++) {
        area+=Cross(p[i]-p[0], p[i+1]-p[0]);
    }
    return area/2;
}

//计算多边形有向面积
double PolygonArea(Point *p,int n) {
    double area=0;
    for (int i=1; i<n-1; i++) {
        area+=Cross(p[i]-p[0], p[i+1]-p[0]);
    }
    return area/2;
}

//计算凸包 P272
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&&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&&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 torad(double deg) {
    return deg/180 *acos(-1);
}

// 过两点p1, p2的直线一般方程ax+by+c=0
// (x2-x1)(y-y1) = (y2-y1)(x-x1)
void getLineGeneralEquation(const Point& p1, const Point& p2, double& a, double& b, double &c) {
    a = p2.y-p1.y;
    b = p1.x-p2.x;
    c = -a*p1.x - b*p1.y;
}

int main() {
    int T,kase=0;
    double x[N],y[N];
    Point P[N],ch[N];
    cin>>T;
    while (T--) {
        kase++;
        int n,pc=0;
        double sx,sy;
        sx=sy=0;
        cin>>n;
        for (int i=0; i<n; i++) {
            scanf("%lf%lf",&x[i],&y[i]);
            P[pc++]=Point(x[i],y[i]);
            sx+=x[i];
            sy+=y[i];
        }
        sort(P, P+n);
        int m=unique(P, P+n)-P;
        m=ConvexHull(P, m, ch);
        double ans=1e9;
        if (m<=2) {
            ans=0;
        } else {
            for (int i=0; i<m; i++) {
                double a,b,c;
                getLineGeneralEquation(ch[i], ch[(i+1)%m], a, b, c);
                ans=min(ans,fabs(a*sx+b*sy+c*n)/sqrt(a*a+b*b));
            }
        }
        printf("Case #%d: %.3lf\n",kase,ans/n);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值