poj1113--凸包

来源:互联网 发布:php开发ide排行榜 编辑:程序博客网 时间:2024/06/04 19:10
题目大意:

      给出平面上若干个点的坐标,你的任务是建一个环形围墙,把所有的点围在里面,且距所有点的距离不小于l。求围墙的最小长度。

思路:

很容易得出答案就是凸包周长+以l为半径的圆的周长。

这里讲一下Andrew算法。

Andrew是Graham算法的变种,而且Andrew更快,且数值稳定性更好。

Andrew算法思想是先将n个点按照x坐标从小到大排序(x相同按照y从小到大),得到一个序列a1,a2,...an,将a1,a2放入ch数组,从a3开始,判断点是否在凸包当前前进方向的左边,如果是,就将点加入ch数组,否则就删除ch中的点直到在左边为止,重复上述操作。值得注意的是,Andrew需要做2次上述过程,第一次求出“下凸包”,第二次求出“上凸包”,合并起来就是完整的凸包。

具体看代码。

 

#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>using namespace std;#define pi acos(-1.0)struct point{    int x,y;    point(int x=0,int y=0):x(x),y(y){}}a[1001],ch[1001];typedef point Vector;point operator - (point a,point b){    return point(a.x-b.x,a.y-b.y);}int cross(Vector a,Vector b){    return(a.x*b.y-a.y*b.x);}double length(Vector a){    return(sqrt((double)a.x*a.x+a.y*a.y));}bool cmp(point a,point b){    return(a.x<b.x||(a.x==b.x&&a.y<b.y));}int n,i,j,k,l,x,y;double sum=0;int main(){    scanf("%d%d",&n,&l);    for(i=1;i<=n;++i)scanf("%d%d",&a[i].x,&a[i].y);    sort(a+1,a+n+1,cmp);    int m=0;    for(i=1;i<=n;++i){        while(m>1&&cross(ch[m]-ch[m-1],a[i]-ch[m-1])<0)m--;        ch[++m]=a[i];    }    k=m;    for(i=n-1;i>=1;--i){        while(m>k&&cross(ch[m]-ch[m-1],a[i]-ch[m-1])<=0)m--;        ch[++m]=a[i];    }    for(i=1;i<m;++i)sum+=length(ch[i+1]-ch[i]);    printf("%.0f\n",sum+2*pi*l);    return 0;}
poj1113