凸包问题——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]; } }