凸包——Andrew算法

凸包——Graham-Scan算法

Andrew算法 (复杂度nlogn)
Andrew算法是一种基于水平序的算法,是Graham-Scan算法的一种变体,性能也更优, 只不过是扫描之前做的处理不同.

1:将所有的点按x坐标从小到大排序,横坐标相同则按y坐标从小到大排.
2:将p[1]和p[2]加入凸包,然后从p[3]开始判断,判断方式与Graham-Scan算法中一致.
3:将所有的点扫描一遍以后,我们就得到一个“下凸包”
4:同理,我们再从p[n-1]开始(p[n]在上面判过就不用判了,但是p[1]要判,最后再把len-1就好了),反着再扫一遍,得到“上凸包”
5:上凸包和下凸包合在一起就是完整的凸包.

代码:

struct Point;
typedef Point Vector;

struct Point{
    double x,y;
    Point(){}
    Point(double a, double b):x(a),y(b){}
    double len(){return sqrt(x*x+y*y);}
    double disToPoint(Point p){return sqrt((x-p.x)*(x-p.x)+(y-p.y)*(y-p.y));}
    void read(){scanf("%lf%lf",&x,&y);}
    Point operator+(Vector v){return {x+v.x,y+v.y};}
    Vector operator-(Point p){return {x-p.x,y-p.y};}
    double operator^(Vector v){return x*v.y-y*v.x;}//叉乘
    double operator*(Vector v){return x*v.x+y*v.y;}//点乘
    Vector operator*(double d){return {x*d,y*d};}
    Vector operator/(double d){return {x/d,y/d};}
    bool operator==(Point p){return cmp(x,p.x)==0&&cmp(y,p.y)==0;}
    bool operator<(Point p){if(cmp(x,p.x)==0) return y<p.y;return x<p.x;}
};
Point p[MAXN];
Point stk[MAXN];
int Andrew(){//点的存储位置[1,n]
    sort(p+1,p+1+n);
    int len=0;
    for (int i=1;i<=n;i++){
        while (len>1&&sgn((stk[len]-stk[len-1])^(p[i]-stk[len-1]))<0) len--;
        stk[++len]=p[i];
    }
    int k=len;
    for (int i=n-1;i>=1;i--){
        while (len>k&&sgn((stk[len]-stk[len-1])^(p[i]-stk[len-1]))<0) len--;
        stk[++len]=p[i];
    }
    len--;
    return len;
}

小结:
紫书上说“和原始的Graham算法相比,Andrew算法更快,且数值稳定性更好”,可能是预处理时Andrew算法比Graham-Scan算法少了叉积这步吧。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值