凸包问题——Graham Scan

Graham Scan 概述:

对于凸多边形的定义不在这里做详细叙述,这里给出算法的实现原理。

Step 1:

找出x值最小的点的集合,从其中找出y值最小的点作为初始点

Step 2:

获得新序列后,p[n]=p[1]

Step 3:

把p[0],p[1],p[2]放入一个栈,从i=3循环到i=n-1,取栈顶两个元素和p[i]连线,如果未形成左旋,栈顶元素退栈,直到栈中元素仅剩两个。

将p[i]压入栈。

C++代码:

#include <algorithm>
#define MAX_N 100000000

int top;//凸包的顶点个数
typedef std::pair<int, int> point;
int dis(point p1, point p2)//两点的距离的平方
{
    return (p1.first - p2.first)*(p1.first - p2.first) + (p1.second - p2.second)*(p1.second - p2.second);
}
point p[MAX_N];
//向量p0p1和向量p0p2的叉积
int  multi(point p1, point p2, point p0)
{
    //x1*y2-x2*y1
    return (p1.first - p0.first) * (p2.second - p0.second) - (p2.first - p0.first) * (p1.second - p0.second);
}
bool cmp(point a, point b)
{
    //点b的极角更大
    if (multi(a, b, p[0]) > 0)
        return true;
    //共线
    if (multi(a, b, p[0]) == 0 && dis(a, p[0]) < dis(b, p[0]))
        return true;
    return false;
}
//Graham_scan的精华
void Graham_scan(point p[], point stack[], int n)
{
    int i, k = 0;
    top = 2;
    //寻找最下且偏左的点
    for (i = 1;i < n;i++)
        if (p[i].second < p[k].second || ((p[i].second == p[k].second) && (p[i].first < p[k].first)))
            k = i;
    //将该点指定为p[0];
    std::swap(p[0], p[k]);
    //按极角从小到大,距离偏短进行排序,此处注意p[0]
    std::sort(p[1], p[n - 1], cmp);
    //核心,方便起见,这里使用我们自建的stack
    stack[0] = p[0], stack[1] = p[1], stack[2] = p[2];
    for (i = 3;i < n;i++)
    {
        while (top > 1 && multi(p[i], stack[top], stack[top - 1]) >= 0)
            top--;
        stack[++top] = p[i];
    }
}
 
原文地址:https://www.cnblogs.com/cielosun/p/5654542.html