您的位置:首页 > 大数据 > 人工智能

凸包 【uva11168】 Airport

2016-12-17 15:59 411 查看
题目大意:

有一些点,找到一条线使所有的点在这条线的同一侧,并且让所有的点到这条线的平均距离最小,并输出最短距离。

题目分析:

我们可以想到如果一条线穿过凸包,那么一定有两个或两个以上的点在这条线的两侧,所以这条直线一定不穿过凸包。

然后可以证明,凸包上的线一定比与凸包相离的线更优。那我们就弄一个凸包,然后枚举凸包上的所有线,比较平均距离值就好啦。

凸包我们可以O(n)的时间求出来。那剩下的问题就是求平均距离的问题了,必须用O(1)的时间求出所有的点到这条线的距离,否则时间复杂度O(n*n)是很TLE的。

但是怎么求呢?

用向量的方法是很令人崩溃的,所以我们要使用数学的力量。

点到直线距离=abs(ax+by+c)/sqrt(a*a+b*b)

我们用点斜式整理一下可以得到:点到直线的距离=abs(kx-y+b)/sqrt(k*k+1)

如果用一般式表示的话需要多计算一个变量,用点斜式可以少计算一个变量,但是需要对没有斜率的时候进行特判(个人喜欢点斜式)。

直线为定直线,所以a和b的值是一样的,所有点都在直线的一侧,所以ax+by+c的正负也是相同的,那么所有点的距离就与这个点有了线性关系。所有点的距离和就是abs(k*∑x+∑y-b*n)/sqrt(k*k+1)。

这样我们维护一下所有x和y的和就可以O(1)时间算出一堆点到一条直线的距离了。

注意事项:

1、这种用横坐标和纵坐标存点,用点斜式存直线的方法在计算几何上貌似并不常用,所以这个方法应该是具有特殊性;

2、在处理栈的时候要小心,不同人可能用不同方式,反正我在这里墨迹了好久;

3、要注意当凸包退化成点或者线段的时候要特判。

代码如下:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdlib>
#define N  12000
#define lar 1023456789
using namespace std;
int T,n;
double sumx,sumy;
struct QAQ{
double x,y;
bool operator < (const QAQ c) const{return x<c.x || (x==c.x && y<c.y);}
}a
,sta
,point
,sti
;
int top,topi;
int main()
{
scanf("%d",&T);
for(int o=1;o<=T;o++)
{
scanf("%d",&n);
sumx=sumy=0;top=topi=0;
for(int i=1;i<=n;i++)
{
scanf("%lf%lf",&a[i].x,&a[i].y);
sumx+=a[i].x; sumy+=a[i].y;
}
sort(a+1,a+1+n);
point[0].x=a[1].x,point[0].y=a[1].y;
QAQ c;
for(int i=2;i<=n;i++)
{
if(a[i].x==point[top-1].x && a[i].y==point[top-1].y) continue;
top++;
do
{
top--;
if(point[top].x==a[i].x) c.x=lar,c.y=a[i].x;
else
{
c.x=(a[i].y-point[top].y)/(a[i].x-point[top].x);
c.y=a[i].y-c.x*a[i].x;
}

}while(top>0 &&(sta[top].x>=c.x || sta[top].x==lar));
sta[++top]=c;point[top].x=a[i].x;point[top].y=a[i].y;
}
point[0].x=a
.x;point[0].y=a
.y;
for(int i=n-1;i>=1;i--)
{
if(a[i].x==point[topi-1].x && a[i].y==point[topi-1].y) continue;
topi++;
do
{
topi--;
if(point[topi].x==a[i].x) c.x=lar,c.y=a[i].x;
else
{
c.x=(a[i].y-point[topi].y)/(a[i].x-point[topi].x);
c.y=a[i].y-c.x*a[i].x;
}

}while(topi>0 &&(sti[topi].x>=c.x || sti[topi].x==lar));
sti[++topi]=c;point[topi].x=a[i].x;point[topi].y=a[i].y;
}
if(top==0 || (top==1 && topi==1)) printf("Case #%d: 0.000\n",o);//特判点和线段
else
{
double ans=lar,cs;
for(int i=1;i<=top;i++)
{
if(sta[i].x==lar) cs=abs(sumx-sta[i].y*n)/n;
else cs=abs(sta[i].x*sumx-sumy+sta[i].y*n)/sqrt(sta[i].x*sta[i].x+1)/n;
if(cs<ans) ans=cs;
}
for(int i=1;i<=topi;i++)
{
if(sti[i].x==lar) cs=abs(sumx-sti[i].y*n)/n;
else cs=abs(sti[i].x*sumx-sumy+sti[i].y*n)/sqrt(sti[i].x*sti[i].x+1)/n;
if(cs<ans) ans=cs;
}
printf("Case #%d: %.3lf\n",o,ans);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: