凸包算法:Graham模板

感觉这个算法比衍生版的Andrew算法优秀。
算法过程大致如下:
首先找到一个y坐标最小的点(y坐标相等就x最小)作为基准点,进行极角排序。这样能保证所有点到这个点的角度都在(-180,180]之间,就不用像Andrew一样维护上下凸壳了。
然后只要维护一下凸壳就好了(如果发现是凹的就退栈)。
最后如果要算面积就分解为三角形来算。
代码如下:

#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1005;
int n,m,stack[maxn],top;
struct Point{
    double x,y;
}a[maxn];
double ans;
bool cmp(Point P1,Point P2){
    double x1=P1.x-a[1].x,y1=P1.y-a[1].y;
    double x2=P2.x-a[1].x,y2=P2.y-a[1].y;
    double p=x1*y2-x2*y1;
    if (p>0.0||(p==0.0&&x1*x1+y1*y1>x2*x2+y2*y2)) return 1;
    return 0;
}
double Cross(Point a,Point b,Point c){
    return (c.x-a.x)*(b.y-a.y)-(c.y-a.y)*(b.x-a.x);
}
void swap_(Point &a,Point &b){
    Point t;
    t.x=a.x,t.y=a.y;
    a.x=b.x,a.y=b.y;
    b.x=t.x,b.y=t.y;
}
double abs_(double x) {if (x<0.0) return -x; return x;}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%lf %lf",&a[i].x,&a[i].y);
    if (n<=2) {printf("0\n"); return 0;}
    int p=1;
    for (int i=2;i<=n;i++)
    if (a[i].y<a[p].y||(a[i].y==a[p].y&&a[i].x<a[p].x)) p=i;
    swap_(a[1],a[p]);
    sort(a+2,a+1+n,cmp);
    m=2;
    for (int i=3;i<=n;i++)
    if (Cross(a[1],a[i-1],a[i])!=0.0) a[++m]=a[i];
    top=3;
    stack[1]=1,stack[2]=2,stack[3]=3;
    for (int i=4;i<=m;i++){
        while (Cross(a[stack[top-1]],a[stack[top]],a[i])>=0) top--;
        stack[++top]=i;
    }
    while (top>=2) ans+=abs_(Cross(a[1],a[stack[top-1]],a[stack[top]])/2),top--;
    printf("%.2lf\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值