凸包判断_Graham扫描算法模板

昨天在做ZOJ 3537的时候,遇到了凸包的判定,用之前的面积判定计算的时候,总是错误,所以学习了一下凸包的判定算法

对我这个几何一点都不会的人来说,叉积判定两个向量方向的地方,只是能记住定理,到现在还是没明白为什么会是这样......

叉积

a × b > 0 则向量a在向量b的顺时针方向

a × b < 0则向量a在向量b的逆时针方向

a × b = 0 则向量a与向量b共线

Graham算法解释

算法步骤:

1、首先找打最左下角的点a,也就是y最小,如果y相同,就去x较小的

2、以a点为基点求出其他所有点的极角,按照极角从小到大排序(这里就可以使用上面叉积的性质,当叉积大于零时,那么a的极角就小于b的极角,因为a在b的顺时针方向)

3、将a,以及极角最小的节点放入队列,按照顺序极角增长的顺序,每次取一个新的节点c,和队列中两个点a(较前面的节点)、b作比较,如果向量bc × 向量ac >= 0 说明:bc在ac顺时针方向或者同方向,那么这时b节点就不能取,因为c节点在b节点的相对较外的位置,b节点删除,这样一直比较,直到c节点处于相对较内的位置,将c节点放入队列;如果向量bc × 向量ac  <0 说明:bc在ac逆时针方向,那么b节点是可取的,c节点直接放入队列

4、最终队列中的点就是凸包上的节点

模板

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <math.h>
#include <queue>
#define INF 0x3f3f3f3f

using namespace std;
typedef long long ll;
const int N = 400;
int n,tot;//n为二维平面上点的个数,tot为凸包上点的个数
struct node
{
    int x,y;
}a[N],p[N];//p[]用来储存凸包

double dis(node a,node b)
{
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}

double multi(node p0,node p1,node p2)
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}

int cmp(node p1,node p2)//极角排序;使用atan2计算会有部分误差,所以使用叉积计算比较精确
{
    int x=multi(a[0],p1,p2);//叉积大于0,表示向量a在向量b的顺时针方向,叉积小于0,向量a在向量b的逆时针方向,等于0,表示两个向量重合!
    if(x>0||(x==0&&dis(p1,a[0])<dis(p2,a[0]))) return 1;
    return 0;
}

void Graham()
{
    int k=0;
    for(int i=0;i<n;i++)
        if(a[i].y<a[k].y||(a[i].y==a[k].y&&a[i].x<a[k].x)) k=i;//得到右下角的那个点的坐标
    swap(a[0],a[k]);
    sort(a+1,a+n,cmp);
    tot=1,p[0]=a[0],p[1]=a[1];
    for(int i=2;i<n;i++)
    {
        while(tot && multi(p[tot-1],p[tot],a[i])<=0) tot--;
        p[++tot]=a[i];
    }
    printf("凸包上的节点:\n");
    for(int i = 0;i <= tot;i ++)
        printf("%d %d\n",p[i].x,p[i].y);
}

int main()
{
    while(~scanf("%d",&n))
    {
        for(int i = 0;i < n;i ++)
            scanf("%d%d",&a[i].x,&a[i].y);
        Graham();
    }
}

参考博客

叉积含义:https://blog.csdn.net/y990041769/article/details/38258761

模板:https://www.cnblogs.com/nyist-TC-LYQ/p/7208054.html

猜你喜欢

转载自blog.csdn.net/li1615882553/article/details/80190066
今日推荐