UVA 11168(凸包算法)

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34780

Problem

给N个点,画一条直线,所有点都在直线一侧(可以在直线上),且到达直线的平均距离最小(实际上就是总距离最小)。输出平均距离,N有10000级别,点坐标挺大。

Solution

首先,求一个凸包,枚举凸包点边,O(1)求出所有点到边的距离,维护最小值即可。

首先,为啥枚举凸包的边是对的?

其次,怎么O(1)求出,设直线返程为Ax+By+C=0, 点 (x0,y0) 到直线的距离为: Ax0+By0+CA2+B2 ,由于点都在直线一侧,所以 (Ax0+By0+C) 的符号都是一样的,只需预处理出 ni=1xi ni=1yi ,就好办啦。

怎么把求两点的一般式?最美的求法。

设y=kx+b, k=y1y2x1x2 ,b=y1-k*x1,kx-y+b=0,则A= k=y1y2x1x2 ,B=-1, C=b=y1y1y2x1x2x1 ,都乘上(x1-x2),得到:A=y1-y2,B=x2-x1,C=x1*y2-y1*x2(叉积,美不美?美不美!………..<–有病)

My code

//Hello. I'm Peter.
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned int uin;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define MAXN
#define N 10100
#define M
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const double eps=1e-9;
int dcmp(double x){
    if(fabs(x)<eps) return 0;
    else if(x<0) return -1;
    else return 1;
}
int n;
struct Point{
    double x,y;
    Point(){};
    Point(double xx,double yy){
        x=xx,y=yy;
    }
};
inline void readPointInt(Point &p){
    int x,y;
    x=read(),y=read();
    p=Point(x,y);
}
typedef Point Vector;
Vector operator+(const Vector a,const Vector b){
    return Vector(a.x+b.x,a.y+b.y);
}
Vector operator -(const Vector a,const Vector b){
    return Vector(a.x-b.x,a.y-b.y);
}
double operator *(const Vector a,const Vector b){
    return a.x*b.x+a.y*b.y;
}
double operator %(const Vector a,const Vector b){
    return a.x*b.y-a.y*b.x;
}
Vector operator*(const Vector a,const double b){
    return Vector(a.x*b,a.y*b);
}
Vector operator*(const double b,const Vector a){
    return Vector(a.x*b,a.y*b);
}
bool operator ==(const Vector a,const Vector b){
    return !dcmp(a.x-b.x)&&!dcmp(a.y-b.y);
}
inline bool comp(const Point a,const Point b){
    if(dcmp(a.x-b.x)) return a.x<b.x;
    else return a.y<b.y;
}
#define lenp res.size()
void Convex_Hull(Point *p,int n,vector<Point>&res){
    res.clear();
    sort(p,p+n,comp);
    for(int i=0;i<n;i++){
        while(lenp>1&&dcmp((res[lenp-1]-res[lenp-2])%(p[i]-res[lenp-1]))<=0) res.pop_back();
        res.push_back(p[i]);
    }
    int k=(int)lenp;
    for(int i=n-2;i>=0;i--){
        while(lenp>k&&dcmp((res[lenp-1]-res[lenp-2])%(p[i]-res[lenp-1]))<=0) res.pop_back();
        res.push_back(p[i]);
    }
    if(lenp>1) res.pop_back();
}
Point p[N];
double A,B,C;
inline void calABC(Point p1,Point p2){
    A=p1.y-p2.y;
    B=p2.x-p1.x;
    C=p1%p2;
}
int main(){
    int T=read();
    for(int kase=1;kase<=T;kase++){
        printf("Case #%d: ",kase);
        n=read();
        double totalx=0,totaly=0;
        for(int i=0;i<n;i++){
            readPointInt(p[i]);
            totalx+=p[i].x;
            totaly+=p[i].y;
        }
        if(n<=2){
            double ans=0.00000;
            printf("%.3f\n",ans);
            continue;
        }
        vector<Point>res;
        Convex_Hull(p,n,res);
        res.push_back(res[0]);//小技巧
        double ansdis=LL;
        for(int i=0;i<lenp-1;i++){
            calABC(res[i],res[i+1]);
            double up=fabs(A*totalx+B*totaly+C*n);
            double down=sqrt(A*A+B*B);
            double totaldis=up/down;
            if(!i) ansdis=totaldis;
            else ansdis=fmin(ansdis,totaldis);
        }
        printf("%.3f\n",ansdis/n);
    }
    return 0;
}

你可能感兴趣的:(凸包,计算几何,一般式,点与直线的距离)