凸包 【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、要注意当凸包退化成点或者线段的时候要特判。
代码如下:
有一些点,找到一条线使所有的点在这条线的同一侧,并且让所有的点到这条线的平均距离最小,并输出最短距离。
题目分析:
我们可以想到如果一条线穿过凸包,那么一定有两个或两个以上的点在这条线的两侧,所以这条直线一定不穿过凸包。
然后可以证明,凸包上的线一定比与凸包相离的线更优。那我们就弄一个凸包,然后枚举凸包上的所有线,比较平均距离值就好啦。
凸包我们可以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; }
相关文章推荐
- UVa 11168 Airport , 凸包
- UVA 11168 Airport(凸包+直线方程)
- UVA 11168 Airport(凸包)
- UVA 11168 Airport 凸包+直线的一般式
- UVA 11168 Airport(凸包+直线两点式转一般式)
- UVA 11168 Airport(凸包+直线两点式转一般式)
- uva 11168 - Airport(凸包)
- Uva 11168 Airport(凸包)
- UVa 11168 Airport , 凸包
- 简单几何(数学公式+凸包) UVA 11168 Airport
- Uva 11168 Airport (凸包)
- UVA 11168 Airport(凸包+直线方程)
- UVA - 11168 Airport (凸包+整理模板)
- UVA11168 Airport 凸包问题
- UVA 11168 Airport 凸包 .
- UVA 11168 Airport(凸包)
- UVa 11168 (凸包+点到直线距离) Airport
- uva 11168 凸包
- uva11168 凸包
- UVa11168 - Airport(凸包+点到直线的距离)