凸包之Andrew算法

博客介绍了凸包概念,即能包围集合中所有点的凸多边形。重点讲解了Andrew算法,它是Graham算法的改进版,复杂度为O(n)。该算法先对坐标点排序,再对有序点扫描,通过叉积判断点能否加入凸包边,最终构建出完整凸包。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

凸包:通俗来讲,就是能够把集合中的点包围在内部的凸多边形

Andrew算法:是Graham算法的改进版,后者复杂度为O(nlogn),而这种算法复杂度为O(n)

这种算法的思想是先对坐标点进行排序,规则是按X从小到大进行排序,如果X相同则按Y从小到大排序
这一段代码如下:

struct Point{
   int x,y;
};

Point P[maxn];

bool cmp(Point x,Point y)
{
    return x.x<y.x||(x.x==y.x&&x.y<y.y);//x从小到大排序,如果x相同则y从小到大排序
}
int main(){
   sort(p,p+n,cmp);
}

然后对于P1,P2,……,Pn这n个有序点进行扫描,具体方法为:
先将P1,P2放入凸包的边,然后从第三个点开始,不断判断Pi是否能加入凸包的边,如果不能,就删除Pi-1,再进行判断,还不行就继续删除,直到剩P1一个点,行的话就继续往下判断
这里写图片描述

如图所示,P1,P2先放入边,加入P3,再加入P4后用叉积判断发现P2,P3,P4构不成边(凹进去了,用叉积判断则表现为P4不在直线P2P3右方),于是删除P3,再判断,发现行了,那么继续往下找。
这里写图片描述

如图所示,找到最后一个点时,凸包的半个壳就出来了,再反过来判断一边,下半个壳也就出来了,这就是Andrew的核心步骤.

完整代码如下:

#include<bits/stdc++.h>
#define maxn 102
using namespace std;
struct Point{
   int x,y;
};

Point p[maxn],ch[maxn];    //后者记录凸包上的点

bool cmp(Point x,Point y)
{
    return x.x<y.x||(x.x==y.x&&x.y<y.y);//x从小到大排序,如果x相同则y从小到大排序
}
int Cross(Point x,Point y,Point z)
{
    int x1=x.x-y.x;
    int y1=x.y-y.y;
    int x2=z.x-y.x;
    int y2=z.y-y.y;
    if((x1*y2-x2*y1)<=0) return 0;//如果不希望在凸包的边上有输入点。把<=改成<
    return 1;
}
int andrew(int n)
{
    sort(p,p+n,cmp);
    int m=0;
    int i;
    for(i=0;i<n;i++)//从左到右扫描
    {
        while( m>1 && !Cross(ch[m-1],ch[m-2],p[i])) m--;
        ch[m++]=p[i];
    }
    int k=m;
    for(i=n-2;i>=0;i--)//从右到左扫描
    {
        while( m>k && !Cross(ch[m-1],ch[m-2],p[i])) m--;
        ch[m++]=p[i];
    }
    if(n>1) m--;//凸包有m个顶点
    return m;
}
int main(){
   int n;
   scanf("%d",&n);
   for(int i=0;i<n;i++)
    scanf("%d %d",&p[i].x,&p[i].y);
   // int ans=andrew(n),ans 为凸包顶点,ch数组为凸包顶点坐标数组 
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值