poj1113--凸包(Andrew)

题目大意:

      给出平面上若干个点的坐标,你的任务是建一个环形围墙,把所有的点围在里面,且距所有点的距离不小于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
",sum+2*pi*l);
    return 0;
}
poj1113
原文地址:https://www.cnblogs.com/gjghfd/p/5634903.html